1 /****^  ***********************************************************
  2         *                                                         *
  3         * Copyright, (C) Honeywell Bull Inc., 1987                *
  4         *                                                         *
  5         * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  6         *                                                         *
  7         * Copyright (c) 1972 by Massachusetts Institute of        *
  8         * Technology and Honeywell Information Systems, Inc.      *
  9         *                                                         *
 10         *********************************************************** */
 11 
 12 
 13 /* format: style4,delnl,insnl,^ifthendo */
 14 channel_manager:
 15      procedure;
 16 
 17 /*  This procedure accepts calls to perform various channel management
 18    functions.  Each such call is directed through a transfer vector
 19    to the appropriate module according to channel type and functional
 20    type.  The specified channel is locked before forwarding the call
 21    and unlocked upon return.
 22 */
 23 
 24 /* Coded 7/31/78 by J. Stern */
 25 /* Tracing added February 1980 */
 26 /* Metering added April 1980 by C. Hornig */
 27 /* Metering corrected October 1980 by Robert Coren to avoid double-counting of output characters */
 28 /* copy_meters control added December 1980 by Robert Coren */
 29 /* Modified 6 Apr 82, W. Olin Sibert, to add TIMER interrupt handling */
 30 
 31 /* Parameters */
 32 
 33 dcl  pm_devx fixed bin;
 34 dcl  pm_info_ptr ptr;
 35 dcl  pm_chain_ptr ptr;
 36 dcl  pm_more_input_flag bit (1) aligned;
 37 dcl  pm_control_type char (*);
 38 dcl  pm_modes_change_list_ptr ptr;
 39 dcl  pm_modes char (*);
 40 dcl  pm_int_type fixed bin;
 41 dcl  pm_int_data bit (72) aligned;
 42 dcl  pm_code fixed bin (35);
 43 
 44 
 45 /* Automatic */
 46 
 47 dcl  queued_entry bit (1) aligned;
 48 dcl  int_type fixed bin;
 49 dcl  devx fixed bin;
 50 dcl  subchan fixed bin;
 51 dcl  locked bit (1) aligned;
 52 dcl  minor_lctep ptr;
 53 dcl  time_in fixed bin (71);
 54 
 55 
 56 /* Based */
 57 
 58 dcl  1 minor_lcte aligned like lcte based (minor_lctep);
 59 
 60 
 61 /* Conditions */
 62 
 63 dcl  cleanup condition;
 64 
 65 
 66 /* Constants */
 67 
 68 dcl  crash_system fixed bin int static options (constant) init (1);
 69 dcl  int_type_names (17) char (16) aligned static options (constant)
 70           init ("dialup", "hangup", "crash", "send_output", "input_available", "accept_input", "input_rejected", "quit",
 71           "line_status", "dial_status", "wru_timeout", "space_available", "ack_echnego_init", "ack_echnego_stop", "timer",
 72           "user", "masked");
 73 
 74 /* External static */
 75 
 76 dcl  pds$process_id bit (36) ext;
 77 dcl  pds$virtual_delta fixed bin (71) ext;
 78 
 79 
 80 /* Builtins */
 81 
 82 dcl  (addr, clock, null, pointer, rel, unspec) builtin;
 83 
 84 
 85 /* Entries */
 86 
 87 dcl  mcs_trace entry options (variable);
 88 dcl  mcs_trace$buffer_chain entry (fixed bin, pointer);
 89 dcl  tty_lock$lock_channel entry (fixed bin, fixed bin (35));
 90 dcl  tty_lock$unlock_channel entry (fixed bin);
 91 dcl  tty_lock$lock_channel_int entry (fixed bin, fixed bin, bit (72) aligned, bit (1) aligned);
 92 dcl  tty_lock$unlock_channel_int entry (fixed bin);
 93 dcl  tty_lock$queue_interrupt entry (fixed bin, fixed bin, bit (72) aligned, fixed bin);
 94 dcl  syserr entry options (variable);
 95 %page;
 96 /* * * * * * * * * * READ * * * * * * * * * * */
 97 
 98 read:
 99      entry (pm_devx, pm_chain_ptr, pm_more_input_flag, pm_code);
100 
101           call setup_major (subchan);
102 
103           if tty_buf.trace.enable
104           then if tty_buf.trace.read
105                then call mcs_trace (pm_devx, "read");
106 
107           on cleanup call unlock_channel ();
108           call lock_channel ();
109           read_ev = make_entry (READ, (lcte.channel_type));
110           call read_ev ((lcte.data_base_ptr), subchan, pm_chain_ptr, pm_more_input_flag, pm_code);
111           if pm_code = 0
112           then if pm_chain_ptr ^= null ()
113                then do blockp = pm_chain_ptr                /* walk chain to count bytes */
114                          repeat (pointer (ttybp, buffer.next)) while (rel (blockp) ^= ""b);
115                     minor_lcte.meters.in_bytes = minor_lcte.meters.in_bytes + buffer.tally;
116                end;
117           call unlock_channel ();
118 
119           if tty_buf.trace.enable
120           then if tty_buf.trace.read
121                then do;
122                     call mcs_trace (pm_devx, "read: ^[code ^d ^;^s^]^[chain at ^p ^;^s^]^[more_input^]", (pm_code ^= 0),
123                          pm_code, (pm_chain_ptr ^= null ()), pm_chain_ptr, pm_more_input_flag);
124                     if tty_buf.trace.data
125                     then call mcs_trace$buffer_chain (pm_devx, pm_chain_ptr);
126                end;
127 
128           call meter_call (minor_lcte.meters.in);
129           return;
130 
131 /* * * * * * * * * * WRITE * * * * * * * * * * */
132 
133 write:
134      entry (pm_devx, pm_chain_ptr, pm_code);
135 
136           call setup_major (subchan);
137 
138           if tty_buf.trace.enable
139           then if tty_buf.trace.write
140                then do;
141                     call mcs_trace (pm_devx, "write: ^p:  ^d bytes ^[etc.^]", pm_chain_ptr, pm_chain_ptr -> buffer.tally,
142                          (pm_chain_ptr -> buffer.next ^= 0));
143                     if tty_buf.trace.data
144                     then call mcs_trace$buffer_chain (pm_devx, pm_chain_ptr);
145                end;
146 
147           on cleanup call unlock_channel ();
148           call lock_channel ();
149           do blockp = pm_chain_ptr                          /* walk chain to count bytes */
150                repeat (pointer (ttybp, buffer.next)) while (rel (blockp) ^= ""b);
151                minor_lcte.meters.out_bytes = minor_lcte.meters.out_bytes + buffer.tally;
152           end;
153           write_ev = make_entry (WRITE, (lcte.channel_type));
154           call write_ev ((lcte.data_base_ptr), subchan, pm_chain_ptr, pm_code);
155 
156           if pm_chain_ptr ^= null ()                        /* multiplexer didn't take it all */
157           then do blockp = pm_chain_ptr                     /* subtract out those it didn't take */
158                     repeat (pointer (ttybp, buffer.next)) while (rel (blockp) ^= ""b);
159                minor_lcte.meters.out_bytes = minor_lcte.meters.out_bytes - buffer.tally;
160           end;
161 
162           call unlock_channel ();
163 
164           if tty_buf.trace.enable
165           then if tty_buf.trace.write
166                then if (pm_chain_ptr ^= null ()) | (pm_code ^= 0)
167                     then call mcs_trace (pm_devx, "write: ^[code ^d ^;^s^]chain left at ^p", pm_code, pm_chain_ptr);
168 
169           call meter_call (minor_lcte.meters.out);
170           return;
171 
172 /* * * * * * * * * * CONTROL * * * * * * * * * */
173 
174 control:
175      entry (pm_devx, pm_control_type, pm_info_ptr, pm_code);
176 
177           call setup_major (subchan);
178 
179           if tty_buf.trace.enable
180           then if tty_buf.trace.control
181                then call mcs_trace (pm_devx, "control: ^a ^p", pm_control_type, pm_info_ptr);
182 
183           on cleanup call unlock_channel ();
184           call lock_channel ();
185           control_ev = make_entry (CONTROL, (lcte.channel_type));
186           call control_ev ((lcte.data_base_ptr), subchan, pm_control_type, pm_info_ptr, pm_code);
187           call unlock_channel ();
188 
189           call meter_call (minor_lcte.meters.control);
190           if pm_control_type = "copy_meters"                /* we have to do something about this */
191           then minor_lcte.saved_meters_ptr -> saved_meters = minor_lcte.meters;
192 
193           else if pm_control_type = "get_meters"            /* this too */
194           then call get_lc_meters;
195 
196           return;
197 
198 /* * * * * * * * * * SET_MODES * * * * * * * * * * */
199 
200 set_modes:
201      entry (pm_devx, pm_modes_change_list_ptr, pm_code);
202 
203           call setup_major (subchan);
204 
205           if tty_buf.trace.enable
206           then if tty_buf.trace.modes
207                then call mcs_trace (pm_devx, "set_modes: ^p", pm_modes_change_list_ptr);
208 
209           on cleanup call unlock_channel ();
210           call lock_channel ();
211           set_modes_ev = make_entry (SET_MODES, (lcte.channel_type));
212           call set_modes_ev ((lcte.data_base_ptr), subchan, pm_modes_change_list_ptr, pm_code);
213           call unlock_channel ();
214 
215           call meter_call (minor_lcte.meters.control);
216           return;
217 
218 /* * * * * * * * * * * CHECK_MODES * * * * * * * * * */
219 
220 check_modes:
221      entry (pm_devx, pm_modes_change_list_ptr, pm_code);
222 
223           call setup_major (subchan);
224 
225           if tty_buf.trace.enable
226           then if tty_buf.trace.modes
227                then call mcs_trace (pm_devx, "check_modes: ^p", pm_modes_change_list_ptr);
228 
229           on cleanup call unlock_channel ();
230           call lock_channel ();
231           check_modes_ev = make_entry (CHECK_MODES, (lcte.channel_type));
232           call check_modes_ev ((lcte.data_base_ptr), subchan, pm_modes_change_list_ptr, pm_code);
233           call unlock_channel ();
234 
235           call meter_call (minor_lcte.meters.control);
236           return;
237 
238 /* * * * * * * * * * * GET_MODES * * * * * * * * * */
239 
240 get_modes:
241      entry (pm_devx, pm_modes, pm_code);
242 
243           call setup_major (subchan);
244 
245           if tty_buf.trace.enable
246           then if tty_buf.trace.modes
247                then call mcs_trace (pm_devx, "get_modes");
248 
249           on cleanup call unlock_channel ();
250           call lock_channel ();
251           get_modes_ev = make_entry (GET_MODES, (lcte.channel_type));
252           call get_modes_ev ((lcte.data_base_ptr), subchan, pm_modes, pm_code);
253           call unlock_channel ();
254 
255           call meter_call (minor_lcte.meters.control);
256           return;
257 
258 /* * * * * * * * * * INTERRUPT * * * * * * * * * * */
259 
260 interrupt:
261      entry (pm_devx, pm_int_type, pm_int_data);
262 
263           queued_entry = "0"b;
264 
265 
266 interrupt_common:
267           int_type = pm_int_type;
268 
269           call setup ();
270 
271           on cleanup call syserr (crash_system, "channel_manager: Cleanup while processing interrupt for devx ^d.", devx);
272           if ^queued_entry
273           then do;
274                call tty_lock$lock_channel_int (devx, int_type, pm_int_data, locked);
275                if ^locked
276                then do;
277                     if tty_buf.trace.enable
278                     then if tty_buf.trace.interrupt
279                          then call mcs_trace (devx, "int: queued ^a ^24.3b", int_type_names (int_type), pm_int_data);
280                     return;                                 /* All finished: interrupt was queued for (locked) channel */
281                end;
282           end;
283 
284           if tty_buf.trace.enable
285           then if tty_buf.trace.interrupt
286                then do;
287                     call mcs_trace (devx, "int: proc ^[queued ^]^a ^24.3b", queued_entry, int_type_names (int_type),
288                          pm_int_data);
289                     if int_type = ACCEPT_INPUT
290                     then if tty_buf.trace.data
291                          then do;
292                               unspec (rtx_info) = pm_int_data;
293                               call mcs_trace$buffer_chain (devx, pointer (ttybp, rtx_info.chain_head));
294                          end;
295                end;
296 
297           interrupt_ev = make_entry (INTERRUPT, (lcte.channel_type));
298           call interrupt_ev ((lcte.data_base_ptr), int_type, pm_int_data);
299 
300           if ^queued_entry
301           then call tty_lock$unlock_channel_int (devx);
302 
303           if /* case */ int_type = ACCEPT_INPUT
304           then do;
305                unspec (rtx_info) = pm_int_data;
306                lcte.meters.in_bytes = lcte.meters.in_bytes + rtx_info.input_count;
307                call meter_interrupt (lcte.meters.in);
308           end;
309           else if int_type = SEND_OUTPUT
310           then do;
311                call meter_interrupt (lcte.meters.out);
312           end;
313           else call meter_interrupt (lcte.meters.control);
314 
315           return;
316 
317 /* * * * * * * * * * QUEUED_INTERRUPT * * * * * * * * * */
318 
319 queued_interrupt:
320      entry (pm_devx, pm_int_type, pm_int_data);             /* called with channel already locked */
321 
322           queued_entry = "1"b;
323           go to interrupt_common;
324 
325 /* * * * * * * * * * INTERRUPT_LATER * * * * * * * * * */
326 
327 interrupt_later:
328      entry (pm_devx, pm_int_type, pm_int_data);
329 
330 /* This entry is used to queue an interrupt for a subchannel unconditionally; the interrupt
331    is processed when it is time to unlock the major channel */
332 
333           int_type = pm_int_type;
334 
335           call setup ();
336 
337           if tty_buf.trace.enable
338           then if tty_buf.trace.interrupt
339                then call mcs_trace (devx, "int: queued ^a ^24.3b", int_type_names (int_type), pm_int_data);
340 
341           on cleanup call syserr (crash_system, "channel_manager: Cleanup while queuing interrupt for devx ^d.", devx);
342 
343           call tty_lock$queue_interrupt ((lcte.major_channel_devx), int_type, pm_int_data, devx);
344           return;
345 ^L
346 /* * * * * * * * * SETUP * * * * * * * * * */
347 
348 setup:
349      proc;
350 
351           locked = "0"b;
352           ttybp = addr (tty_buf$);
353           lctp = tty_buf.lct_ptr;
354 
355           time_in = clock () - pds$virtual_delta;
356 
357           devx = pm_devx;
358           if devx < 1 | devx > lct.max_no_lctes
359           then call syserr (crash_system, "channel_manager: Invalid devx specified.  ^o", devx);
360 
361           lctep = addr (lct.lcte_array (devx));
362 
363           cmtvp = addr (cmtv$cmtv);
364 
365      end setup;                                             /* setup */
366 
367 /* * * * * * * * * * * SETUP_MAJOR * * * * * * * ** */
368 
369 setup_major:
370      proc (subchan);
371 
372 dcl  subchan fixed bin;
373 
374 
375           call setup ();
376           minor_lctep = lctep;
377           if lcte.lock ^= pds$process_id
378           then call syserr (crash_system, "channel_manager: Channel not locked by process. (devx = ^o)", devx);
379           subchan = lcte.subchannel;
380 
381           devx = lcte.major_channel_devx;
382           lctep = addr (lct.lcte_array (devx));
383 
384      end setup_major;                                       /* setup_major */
385 ^L
386 /* * * * * * * * * * METER_CALL * * * * * * * * * */
387 
388 meter_call:
389      procedure (Meters);
390 dcl  1 Meters aligned like lcte.meters.in;
391 
392           Meters.calls = Meters.calls + 1;
393           Meters.call_time = Meters.call_time + clock () - pds$virtual_delta - time_in;
394           return;
395 
396 /* * * * * * * * * * METER_INTERRUPT * * * * * * * * * */
397 
398 meter_interrupt:
399      entry (Meters);
400 
401           Meters.interrupts = Meters.interrupts + 1;
402           Meters.interrupt_time = Meters.interrupt_time + clock () - pds$virtual_delta - time_in;
403           return;
404      end meter_call;
405 ^L
406 /* * * * * * * * * * GET_LC_METERS * * * * * * * * * * */
407 
408 get_lc_meters:
409      proc;
410 
411 /* return logical channel meters in response to get_meters order */
412 
413 dcl  lcmp ptr;
414 dcl  info_ptr ptr;
415 
416           info_ptr = pm_info_ptr;
417           info_ptr -> get_comm_meters_info.parent_type = lcte.channel_type;
418           lcmp = info_ptr -> get_comm_meters_info.logical_chan_ptr;
419           lcmp -> logical_chan_meters.current_meters = minor_lcte.meters;
420           lcmp -> logical_chan_meters.saved_meters = minor_lcte.saved_meters_ptr -> saved_meters;
421           return;
422      end get_lc_meters;
423 ^L
424 /* * * * * * * * * * MAKE_ENTRY * * * * * * * * * * */
425 
426 make_entry:
427      proc (entry_type, chan_type) returns (entry variable); /* kludges together an entry variable */
428 
429 dcl  entry_type fixed bin;
430 dcl  chan_type fixed bin;
431 
432 dcl  code_ptr ptr;
433 dcl  code_word fixed bin based (code_ptr);
434 
435 dcl  new_entry entry variable;
436 dcl  1 entry_var aligned,
437        2 code_ptr ptr,
438        2 env_ptr ptr;
439 
440 
441           code_ptr = addr (cmtv.entries (entry_type, cmtv.chan_type_index (chan_type)));
442           if code_word = 0                                  /* undefined entry point */
443           then new_entry = undefined_entry;
444           else do;
445                entry_var.code_ptr = code_ptr;
446                entry_var.env_ptr = null;
447                unspec (new_entry) = unspec (entry_var);
448           end;
449           return (new_entry);
450      end make_entry;                                        /* get_entry */
451 
452 undefined_entry:
453      procedure;                                             /* for bad cmtv pointers */
454           return;
455      end undefined_entry;
456 ^L
457 /* * * * * * * * * * * * LOCK_CHANNEL * * * * * * * * * */
458 
459 lock_channel:
460      proc;
461 
462 dcl  code fixed bin (35);
463 
464 
465           if lcte.special_lock                              /* not for us to lock */
466           then return;
467 
468           call tty_lock$lock_channel (devx, code);
469           if code ^= 0
470           then call syserr (crash_system, "channel_manager: Cannot lock channel for devx ^o (code = ^o)", devx, code);
471           locked = "1"b;
472 
473      end lock_channel;                                      /* lock_channel */
474 
475 /* * * * * * * * * * * UNLOCK_CHANNEL * * * * * * * * * * */
476 
477 unlock_channel:
478      proc;
479 
480           if locked
481           then call tty_lock$unlock_channel (devx);
482           locked = "0"b;
483 
484      end unlock_channel;                                    /* unlock_channel */
485 ^L
486 %include lct;
487 ^L
488 %include cmtv;
489 ^L
490 %include tty_buf;
491 ^L
492 %include mcs_interrupt_info;
493 %include tty_buffer_block;
494 %include get_comm_meters_info;
495 
496      end;                                                   /* channel_manager_ */
497 ^L
498 /* BEGIN MESSAGE DOCUMENTATION
499 
500    Message:
501    channel_manager: Cleanup while processing interrupt for devx N.
502 
503    S:     $crash
504 
505    T:     $run
506 
507    M:     The cleanup condition was signalled while processing an
508    interrupt for the channel with devx N.
509 
510    A:     $inform
511 
512 
513    Message:
514    channel_manager: Error while processing interrupt for devx N.  REASON
515 
516    S:     $crash
517 
518    T:     $run
519 
520    M:     An error occurred while processing an interrupt for the channel
521    with devx N.  The specific kind of error is explained by REASON.
522 
523    END MESSAGE DOCUMENTATION */