Opened 4 weeks ago

Closed 10 days ago

#393 closed defect (fixed)

absentee_listener_ has a temp_segment leak

Reported by: Gary Dixon Owned by: Eric Swenson
Priority: major Milestone:
Component: Standard Library Version: MR12.5
Keywords: Cc:

Description (last modified by Gary Dixon)

While developing an exec_com to test dump_segment and ring_zero_dump,
I checked on status of temporary segments in my process directory.
My current stack shows only an interrupted emacs editing session.

ts -bf
quit condition:
234|13340   pl1_signal_$pl1_signal_from_ops_|776 (bound_library_1_|13712)
234|12320   lisp_fault_handler_$ioc|1265 (bound_lisp_intrprtr_|17521)
234|12240   lisp_subr_tv_$..lisp..|2652 (bound_lisp_intrprtr_|2652)
234|11760   lisp|1076 (bound_lisp_intrprtr_|35014)
234|11460   lisp$lisp|244 (bound_lisp_intrprtr_|34162)
234|11360   forward_command_|70 (bound_multics_emacs_|136514)
234|10260   emacs$emacs|2401 (bound_multics_emacs_|141121)
234|10140   emacs_tv_$emacs|37 (bound_emacs_full_|37)
234|5340    command_processor_$read_list|10312 (bound_multics_bce_|10312)
234|4360    command_processor_$complex_command_processor|2543 (bound_multics_bce_|2543)
234|3420    command_processor_$command_processor_|1227 (bound_multics_bce_|1227)
234|2700    abbrev$abbrev_processor|6105 (bound_command_loop_|14103)
234|2400    listen_$listen_|554 (bound_command_loop_|34522)
234|2000    initialize_process_$initialize_process_|704 (bound_process_init_|704)

However, past usage in my process shows 57 temp segments in existence, and only 6 are free. The majority of them were claimed by ec_input_ operations.

list_temp_segments

          57 Segments,  6 Free

!BBBKbcHFWxfwjm.temp.0305  command_processor_
!BBBKbcHFXHQmDB.temp.0362  emacs
!BBBKbcHFXHWDLw.temp.0363  emacs
!BBBKbcHFXQKWkm.temp.0433  emacs
!BBBKbcHFXQKdqf.temp.0434  emacs
!BBBKbcHFXQQQJQ.temp.0440  emacs
!BBBKbcHFcglBfc.temp.0446  command_processor_
!BBBKbcHFcgzxdl.temp.0454  command_processor_
!BBBKbcHFchBGJp.temp.0455  command_processor_
!BBBKbcHFlpHmpB.temp.0457  ec_input_ (area)
!BBBKbcHKLmmBGD.temp.0477  ec_input_ (area)
!BBBKbcHKPddDbh.temp.0500  ec_input_ (area)
!BBBKbcHKXgkmXL.temp.0501  ec_input_ (area)
!BBBKbcHKhNnXgh.temp.0502  ec_input_ (area)
!BBBKbcHKjQFcQd.temp.0503  ec_input_ (area)
!BBBKbcHKmpMGcn.temp.0504  ec_input_ (area)
!BBBKbcHKwWbkBW.temp.0505  ec_input_ (area)
!BBBKbcHLHNqJkP.temp.0506  ec_input_ (area)
!BBBKbcHLHPLQnn.temp.0507  ec_input_ (area)
!BBBKbcHLHPLckF.temp.0510  ec_input_ (area)
!BBBKbcHLKqFlCh.temp.0511  ec_input_ (area)
!BBBKbcHLPCJbqp.temp.0512  ec_input_ (area)
!BBBKbcHLgXlKfK.temp.0565  ec_input_ (area)
!BBBKbcHLqdwQNd.temp.0566  ec_input_ (area)
!BBBKbcHLqfNBMP.temp.0570  ec_input_ (area)
!BBBKbcHMLDggcb.temp.0571  ec_input_ (area)
!BBBKbcHMcGgMgg.temp.0572  ec_input_ (area)
!BBBKbcHNQMKqkQ.temp.0573  ec_input_ (area)
!BBBKbcHNZhbKXd.temp.0574  ec_input_ (area)
!BBBKbcHNZhgHjJ.temp.0575  ec_input_ (area)
!BBBKbcHNbzlfqj.temp.0576  ec_input_ (area)
!BBBKbcHNbzqQFd.temp.0577  ec_input_ (area)
!BBBKbcHNhfZpxl.temp.0600  ec_input_ (area)
!BBBKbcHNhffjCx.temp.0601  ec_input_ (area)
!BBBKbcHNlznBFG.temp.0602  ec_input_ (area)
!BBBKbcHNlzwpKn.temp.0603  ec_input_ (area)
!BBBKbcHNpCHmNb.temp.0604  ec_input_ (area)
!BBBKbcHNpCPGCl.temp.0605  ec_input_ (area)
!BBBKbcHPGWJCbh.temp.0606  ec_input_ (area)
!BBBKbcHPGWNCQW.temp.0607  ec_input_ (area)
!BBBKbcHPJJFzxB.temp.0610  ec_input_ (area)
!BBBKbcHPJJKzpG.temp.0611  ec_input_ (area)
!BBBKbcHPMbmlQf.temp.0612  ec_input_ (area)
!BBBKbcHPMbwqnn.temp.0613  ec_input_ (area)
!BBBKbcHPPNqQCD.temp.0614  ec_input_ (area)
!BBBKbcHPPPBWHh.temp.0615  ec_input_ (area)
!BBBKbcHPccZcpJ.temp.0616  ec_input_ (area)
!BBBKbcHPccflDz.temp.0617  ring_zero_dump.1 (ring_zero_dump
!BBBKbcHQBdpnJK.temp.0624  ring_zero_dump.1 (ring_zero_dump
!BBBKbcHQgKCwQD.temp.0626  emacs
!BBBKbcHWnjHwKP.temp.0625  ring_zero_dump.1 (ring_zero_dump

ls [pd]>*.temp.* -records -dtem

Segments = 59, Records = 70.

06/21/26 10:47    1  !BBBKbcHFWxfwjm.temp.0305
06/21/26 10:47    1  !BBBKbcHFWzDFBB.temp.mail_system
06/21/26 10:47    3  !BBBKbcHFWzDZJW.temp.mail_system
06/21/26 10:47    1  !BBBKbcHFXHQmDB.temp.0362
06/21/26 10:47    1  !BBBKbcHFXHWDLw.temp.0363
06/21/26 10:47    1  !BBBKbcHFXQKWkm.temp.0433
06/21/26 10:47    1  !BBBKbcHFXQKdqf.temp.0434
06/21/26 10:47    2  !BBBKbcHFXQQQJQ.temp.0440
06/21/26 10:49    1  !BBBKbcHFcglBfc.temp.0446
06/21/26 10:49    1  !BBBKbcHFcgzxdl.temp.0454
06/21/26 10:49    1  !BBBKbcHFchBGJp.temp.0455
06/21/26 11:56    1  !BBBKbcHFlpHmpB.temp.0457
06/21/26 11:57    1  !BBBKbcHKLmmBGD.temp.0477
06/21/26 11:59    1  !BBBKbcHKPddDbh.temp.0500
06/21/26 12:03    1  !BBBKbcHKXgkmXL.temp.0501
06/21/26 12:03    1  !BBBKbcHKhNnXgh.temp.0502
06/21/26 12:05    1  !BBBKbcHKjQFcQd.temp.0503
06/21/26 12:07    1  !BBBKbcHKmpMGcn.temp.0504
06/21/26 12:12    1  !BBBKbcHKwWbkBW.temp.0505
06/21/26 12:13    1  !BBBKbcHLHNqJkP.temp.0506
06/21/26 12:15    1  !BBBKbcHLHPLQnn.temp.0507
06/21/26 12:20    1  !BBBKbcHLHPLckF.temp.0510
06/21/26 12:21    1  !BBBKbcHLKqFlCh.temp.0511
06/21/26 12:23    1  !BBBKbcHLPCJbqp.temp.0512
06/21/26 12:25    1  !BBBKbcHLgXlKfK.temp.0565
06/21/26 12:31    1  !BBBKbcHLqdwQNd.temp.0566
06/21/26 12:32    1  !BBBKbcHLqfNBMP.temp.0570
06/21/26 12:36    1  !BBBKbcHMLDggcb.temp.0571
06/21/26 12:52    1  !BBBKbcHMcGgMgg.temp.0572
06/21/26 12:53    1  !BBBKbcHNQMKqkQ.temp.0573
06/21/26 12:53    1  !BBBKbcHNZhbKXd.temp.0574
06/21/26 12:54    1  !BBBKbcHNZhgHjJ.temp.0575
06/21/26 12:54    1  !BBBKbcHNbzlfqj.temp.0576
06/21/26 12:57    1  !BBBKbcHNbzqQFd.temp.0577
06/21/26 12:57    1  !BBBKbcHNhfZpxl.temp.0600
06/21/26 12:59    1  !BBBKbcHNhffjCx.temp.0601
06/21/26 12:59    1  !BBBKbcHNlznBFG.temp.0602
06/21/26 13:00    1  !BBBKbcHNlzwpKn.temp.0603
06/21/26 13:00    1  !BBBKbcHNpCHmNb.temp.0604
06/21/26 13:05    1  !BBBKbcHNpCPGCl.temp.0605
06/21/26 13:05    1  !BBBKbcHPGWJCbh.temp.0606
06/21/26 13:06    1  !BBBKbcHPGWNCQW.temp.0607
06/21/26 13:06    1  !BBBKbcHPJJFzxB.temp.0610
06/21/26 13:08    1  !BBBKbcHPJJKzpG.temp.0611
06/21/26 13:08    1  !BBBKbcHPMbmlQf.temp.0612
06/21/26 13:09    1  !BBBKbcHPMbwqnn.temp.0613
06/21/26 13:09    1  !BBBKbcHPPNqQCD.temp.0614
06/21/26 13:12    1  !BBBKbcHPPPBWHh.temp.0615
06/21/26 13:12    1  !BBBKbcHPccZcpJ.temp.0616
06/21/26 13:12    2  !BBBKbcHPccflDz.temp.0617
06/21/26 13:21    2  !BBBKbcHQBdpnJK.temp.0624
06/21/26 13:32   13  !BBBKbcHQgKCwQD.temp.0626
06/21/26 13:53    1  !BBBKbcHWnjHwKP.temp.0625
06/21/26 13:54    0  !BBBKbcHWqwCdKj.temp.0627
06/21/26 14:14    0  !BBBKbcHZBblQlQ.temp.0632
06/21/26 14:14    0  !BBBKbcHZBblhmp.temp.0634
06/21/26 14:14    0  !BBBKbcHZBblpnZ.temp.0635
06/21/26 14:14    0  !BBBKbcHZBbwMxW.temp.0637
06/21/26 14:25    0  !BBBKbcHZdwmzKC.temp.0647

I suspect that:

  • one gets created each time the exec_com command is called; and
  • that temp seg isn't getting released correctly.

I have only the above proof of this suspicion at the moment, but I feel this temp segment releasing error should be documented. While temp segment sizes in the process directory are small (usually 1 page long), the leak could cause the process to eventually run out of available segment numbers. The highest user process segment number allowed is segno 1777_o = 1023_d (limited by the size of user process dseg: 2 pages with each SDW in the array occupying 2 words).

Change History (5)

comment:1 by Gary Dixon, 4 weeks ago

Description: modified (diff)

comment:2 by Gary Dixon, 4 weeks ago

To test my theory, I invoked the exec_com I was developing. For some reason, it went into a loop which created 4 more temp segments (for a total of 63 in use, and 2 free).

list_temp_segments

          63 Segments,  2 Free

!BBBKbcHFWxfwjm.temp.0305  command_processor_
!BBBKbcHFXHQmDB.temp.0362  emacs
!BBBKbcHFXHWDLw.temp.0363  emacs
!BBBKbcHFXQKWkm.temp.0433  emacs
!BBBKbcHFXQKdqf.temp.0434  emacs
!BBBKbcHFXQQQJQ.temp.0440  emacs
!BBBKbcHFcglBfc.temp.0446  command_processor_
!BBBKbcHFcgzxdl.temp.0454  command_processor_
!BBBKbcHFchBGJp.temp.0455  command_processor_
!BBBKbcHFlpHmpB.temp.0457  ec_input_ (area)
!BBBKbcHKLmmBGD.temp.0477  ec_input_ (area)
!BBBKbcHKPddDbh.temp.0500  ec_input_ (area)
!BBBKbcHKXgkmXL.temp.0501  ec_input_ (area)
!BBBKbcHKhNnXgh.temp.0502  ec_input_ (area)
!BBBKbcHKjQFcQd.temp.0503  ec_input_ (area)
!BBBKbcHKmpMGcn.temp.0504  ec_input_ (area)
!BBBKbcHKwWbkBW.temp.0505  ec_input_ (area)
!BBBKbcHLHNqJkP.temp.0506  ec_input_ (area)
!BBBKbcHLHPLQnn.temp.0507  ec_input_ (area)
!BBBKbcHLHPLckF.temp.0510  ec_input_ (area)
!BBBKbcHLKqFlCh.temp.0511  ec_input_ (area)
!BBBKbcHLPCJbqp.temp.0512  ec_input_ (area)
!BBBKbcHLgXlKfK.temp.0565  ec_input_ (area)
!BBBKbcHLqdwQNd.temp.0566  ec_input_ (area)
!BBBKbcHLqfNBMP.temp.0570  ec_input_ (area)
!BBBKbcHMLDggcb.temp.0571  ec_input_ (area)
!BBBKbcHMcGgMgg.temp.0572  ec_input_ (area)
!BBBKbcHNQMKqkQ.temp.0573  ec_input_ (area)
!BBBKbcHNZhbKXd.temp.0574  ec_input_ (area)
!BBBKbcHNZhgHjJ.temp.0575  ec_input_ (area)
!BBBKbcHNbzlfqj.temp.0576  ec_input_ (area)
!BBBKbcHNbzqQFd.temp.0577  ec_input_ (area)
!BBBKbcHNhfZpxl.temp.0600  ec_input_ (area)
!BBBKbcHNhffjCx.temp.0601  ec_input_ (area)
!BBBKbcHNlznBFG.temp.0602  ec_input_ (area)
!BBBKbcHNlzwpKn.temp.0603  ec_input_ (area)
!BBBKbcHNpCHmNb.temp.0604  ec_input_ (area)
!BBBKbcHNpCPGCl.temp.0605  ec_input_ (area)
!BBBKbcHPGWJCbh.temp.0606  ec_input_ (area)
!BBBKbcHPGWNCQW.temp.0607  ec_input_ (area)
!BBBKbcHPJJFzxB.temp.0610  ec_input_ (area)
!BBBKbcHPJJKzpG.temp.0611  ec_input_ (area)
!BBBKbcHPMbmlQf.temp.0612  ec_input_ (area)
!BBBKbcHPMbwqnn.temp.0613  ec_input_ (area)
!BBBKbcHPPNqQCD.temp.0614  ec_input_ (area)
!BBBKbcHPPPBWHh.temp.0615  ec_input_ (area)
!BBBKbcHPccZcpJ.temp.0616  ec_input_ (area)
!BBBKbcHPccflDz.temp.0617  ring_zero_dump.1 (ring_zero_dump
!BBBKbcHQBdpnJK.temp.0624  ring_zero_dump.1 (ring_zero_dump
!BBBKbcHQgKCwQD.temp.0626  emacs
!BBBKbcHWnjHwKP.temp.0625  ring_zero_dump.1 (ring_zero_dump
!BBBKbcHWqwCdKj.temp.0627  ec_input_ (area)
!BBBKbcHZBblQlQ.temp.0632  ec_input_ (area)
!BBBKbcHZBblhmp.temp.0634  ec_input_ (area)
!BBBKbcHZBblpnZ.temp.0635  ec_input_ (area)
!BBBKbcHZBbwMxW.temp.0637  ec_input_ (area)
!BBBKbcHZdwmzKC.temp.0647  ec_input_ (area)
!BBBKbcHcfHpzwP.temp.0651  ec_input_ (area)
!BBBKbcHcfHqxkD.temp.0650  ec_input_ (area)
!BBBKbcHcfHwqzD.temp.0654  ec_input_ (area)
!BBBKbcHcfHxpfl.temp.0655  ec_input_ (area)

comment:3 by Gary Dixon, 4 weeks ago

Summary: absentee_listener_ appears to have a temp_segment leakabsentee_listener_ has a temp_segment leak

comment:4 by Gary Dixon, 4 weeks ago

I believe the cause of the temp segment leak stems from the method used by absentee_listen_$execute_handler to create an almost new abs_data structure without preserving contents of the abs_data.work_area in the original abs_data structure.

The abs_data structure ends with an 800 word area called abs_data.work_area. Aspects of this structure important to this issue are shown by an excerpt from abs_io_data.incl.pl1.

declare   abs_data_ptr                  ptr;

declare   1 abs_data                    aligned based (abs_data_ptr),
            2 version                   fixed bin,          /* Version = 1                                              */
            2 io_module_name            char (32) varying,  /* either "abs_io_" or "ec_input_"                          */
            ...
declare   abs_data_ptr                  ptr;

declare   1 abs_data                    aligned based (abs_data_ptr),
            2 version                   fixed bin,          /* Version = 1                                              */
            2 io_module_name            char (32) varying,  /* either "abs_io_" or "ec_input_"                          */
            ...
            2 work_area                 area (800);         /* extensible area for args, etc.                           */

declare   abs_data_version_1            fixed bin static options (constant) initial (1),
          Work_area_size                fixed bin static options (constant) initial (800);

An abs_data structure is allocated whenever an exec_com script (or absentee job) begins execution. That same structure is used for allocations while the script runs, unless an
on-unit established by the script gets invoked by a signal in its CONDITION_list.

&on CONDITION_LIST &begin LINES &end

To execute the LINES inside the on-unit, the absentee_listen_$execute_handler is called to establish a run-time environment in which to execute the on-unit lines. This is the equivalent of pushing a new stack frame onto the user stack in which to run a PL/I on-unit. The on-unit has access to the variables and labels setup by the outer script. So when the execute_handler entry allocates a new abs_data structure, it copies all of the data from the outer-script's abs_data into the new abs_data structure to capture this outer information. It then initializes some elements of the new structure for the on-unit's environment, while preserving data for the outer-script.

execute_handler: entry (P_exec_com_info_ptr, P_ec_info_ptr, P_abs_data_ptr, P_handler_node_ptr,
                         P_condition_info_ptr, P_goto_label_ptr, P_goto_label_len, P_continue_to_signal_sw, P_code);

/* This entry point executes the text of an &on unit as if it were a separate exec_com, remembering whether it
   has exited by means of a nonlocal &goto */

          entry_point_name = "execute_handler";

          P_goto_label_ptr = null;

          state = IN_OUTER_PROC;
          initialized = "0"b;

          exec_com_info_ptr = P_exec_com_info_ptr;
          ec_info = P_ec_info_ptr -> ec_data;
          handler_node_ptr = P_handler_node_ptr;

/* Set up a new abs_data for executing the handler */

          abs_data_ptr = null;

          on cleanup call clean_up;

          call abs_io_$allocate_abs_data (abs_data_ptr);

          abs_data = P_abs_data_ptr -> abs_data;            /* will use some old information */

          abs_data.active = "0"b;

          call abs_io_$initialize_abs_data (abs_data_ptr);  /* and some new information */

          initialized = "1"b;
          ...

The abs_data.work_area created as an empty area which that abs_data structure is allocated is then overwritten by the outer-script's work_area. Notice the comment attached to that statement:

/* use the same area; copy it back when done */

That comment is an important clue to the losing data about components of the extensible area.

          abs_data.work_area = P_abs_data_ptr -> abs_data.work_area;  
              /* use the same area; copy it back when done */

          saved_abs_data_ptr, abs_data.on_info.parent_abs_data_ptr = ec_info.switch_ptr -> iocb.attach_data_ptr;
          ec_info.switch_ptr -> iocb.attach_data_ptr = abs_data_ptr;

          ec_info.call_ready_proc = "0"b;

          go to COMMON;

The abs_data.work_area is an extensible area and has an extend_block allocated in the work_area (and pointed to by the area_header) to locate additional components of the area. From area_structures.incl.pl1, that extend_block is shown below.

dcl 1 extend_block aligned based (extend_blockp),           /* contents of extend block for extensible areas */
    2 first_area ptr unal,                                  /* pointer to first area */
    2 next_area ptr unal,                                   /* pointer to next area in chain */
    2 sequence_no fixed bin,                                /* sequence number for this component */
    2 name char (32),                                       /* owner of the area */
    2 pad fixed;                                            /* brings it to an even, 12 word allocation */

When the 800 words of the abs_data.work_area are filled with allocations, then the allocator calls define_area_ to add an extension area component in a temporary segment. That new area component also includes an extend_block. But the extend_block in the first area component gets updated to with information about this latest extension component being created.

Because nothing has been allocated in the new abs_data.work_area before it is overwritten by the abs_data.work_area for the outer-script, no loss of information has occurred as yet.

However, now LINES from the &on-unit being executed are read and invoked. These do cause allocations in the 800 word abs_data.work_area, which sometimes require adding a new component area to the extensible area. Such addition is recorded in the extend_block of the 800 word abs_data.work_area, and linked to any prior components in the extensible area. As yet, no data has been lost.

When execution of the &on-unit LINES finishes, absentee_listen_ jumps to the EGRESS label, which invokes the finish_up subroutine. This routine has the job of disposing of the new abs_data structure, and restoring use of the prior abs_data structure. According to the comment highlighted above, contents of the 800 word first component of the abs_data.work_area is supposed to be copied back into the outer-script's work_area. But finish_up frees the new abs_data structure WITHOUT copying it back.

EGRESS:
          call finish_up ();

          return;
          ...

finish_up: procedure ();
 ...
          if initialized then
            if abs_data_ptr ^= null then
               if entry_point_name = "execute_handler" then do;

                    P_continue_to_signal_sw = abs_data.on_info.continue_to_signal_sw;

                    if abs_data.goto_sw then do;            /* leaving &on unit via &goto */
                                                            /* label must be allocated in parent's area */
                         allocate goto_label in (saved_abs_data_ptr -> abs_data.work_area)
                              set (P_goto_label_ptr);       /* set args of absentee_listen_$execute_handler */
                         P_goto_label_ptr -> goto_label = abs_data.goto_label_ptr -> goto_label;
                         P_goto_label_len = abs_data.goto_label_len;

                         saved_abs_data_ptr -> abs_data.goto_statement_pos = abs_data.goto_statement_pos
                              + charno (abs_data.input_string.ptr)
                              - charno (saved_abs_data_ptr -> abs_data.input_string.ptr);
                         saved_abs_data_ptr -> abs_data.goto_statement_len = abs_data.goto_statement_len;
                    end;

                    saved_abs_data_ptr -> abs_data.output_file = abs_data.output_file;
                    saved_abs_data_ptr -> abs_data.variables_ptr = abs_data.variables_ptr;

                    free abs_data;                          /* free the &on unit's private abs_data */
                                                            /* and restore the parent's: */

                    abs_data_ptr, ec_info.switch_ptr -> attach_data_ptr = saved_abs_data_ptr;
               end;

          return;

end finish_up;

Thus any changes to the extend_block in the new abs_data.work_area are lost. This might explain why an extension component of the work_area never gets released.

The abs_data structure for the outer-most script finally gets freed when the ec_input_ I/O switch is detached. The cleanup procedure in abs_io_.pl1 is finally called to release components of the extensible area, and free the outer-most abs_data structure.

clean_up:
     procedure ();

declare   p                             ptr;

          if abs_data_ptr ^= null ()
          then do;
                    if initialized
                    then do;
                              if abs_data.attach.save_ptr ^= null ()
                              then call iox_$destroy_iocb (abs_data.attach.save_ptr, status);
                              p = input_string.ptr;         /* TEMP: this can be removed when terminate_noname is fixed */
                              input_string.ptr = null ();
                              if p ^= null () then call hcs_$terminate_noname (p, status);
                              call release_area_ (addr (abs_data.work_area));
                         end;
                    free abs_data;
               end;

          return;

end clean_up;
Version 0, edited 4 weeks ago by Gary Dixon (next)

comment:5 by Eric Swenson, 10 days ago

Resolution: fixed
Status: newclosed
Note: See TracTickets for help on using tickets.