program testq; { Test multi-tasking under MP/M with Pascal MT+86 Queues used for synchronization TERMINATE used for subtask termination } const pd_max = 61; {max byte address in process descriptor table} uda_max = 255; {max byte address in user data area table} def_prior = 201; {default process priority} qd_nmsgs = 5; {max messages in queue} q_open = 135; q_delete = 136; q_read = 137; q_cond_read = 138; q_write = 139; q_cond_write = 140; type name_type = packed array [1..8] of char; pd_size = 0..pd_max; {Process Descriptor} pd_type = record case boolean of true: (z1: packed array [1..5] of byte; prior: byte; flag: word; name: name_type; uda: word; user, disk: byte; z2: packed array [1..12] of byte; cns: byte; z3: packed array [1..3] of byte; list: byte; z4: packed array [1..15] of byte; cns2: byte; z5: byte; name2: name_type); false: (ray: array [pd_size] of byte); end; uda_size = 0..uda_max; {User Data Area for Process} uda_type = array [uda_size] of byte; ptr = ^integer; pdp = ^pd_type; udap = ^uda_type; qdp = ^qd_type; qpbp = ^qpb_type; qdmp = ^qd_msg; ptrtype = (ptrp, pdpp, udapp, qdpp, qpbpp, qdmpp, offseg); pointer = record {kludge to allow any type of pointer reference} case ptrtype of ptrp: (pptr: ptr); pdpp: (pdpp: pdp); udapp: (puda: udap); qdpp: (pqdp: qdp); qpbpp: (pqpb: qpbp); qdmpp: (pqdm: qdmp); offseg: (off: word; seg: word) end; qd_msg = record {actual Queue Message for this example} name: name_type; count: integer end; qd_type = record {Queue Descriptor block} z1: longint; flags: word; name: name_type; msglen: integer; nmsgs: integer; z3, z2: longint; z4: word; end; qpb_type = record {Queue Parameter Block} z: word; qid: word; nmsgs: integer; buffer: word; name: name_type; end; var uda_c, uda_b, uda_a: uda_type; {user data area for sub-process} pd_c, pd_b, pd_a: pd_type; {process descriptor for sub-process} qd: qd_type; {queue descriptor block} qpb: qpb_type; {queue parameter block} qmsg: qd_msg; {queue message} done_c, done_b, done_a: boolean; {communication flags} writ_c, writ_b, writ_a: boolean; external procedure init_mpm_util(size: integer); external procedure fix_stack(taskp: ptr; var uda: uda_type; size: integer); external procedure delay(ticks: integer); external procedure dispatch; external procedure terminate; external function create_process(var pd: pd_type): boolean; external function set_priority(priority: byte): boolean; external function queue_make(var qd: qd_type): boolean; external function queue_oper(op: byte; var qpb: qpb_type): boolean; { *********************************************************** } procedure startup(var pd: pd_type; var uda: uda_type; task: ptr; name: string; priority: integer; size: integer); var i: integer; p: pointer; begin for i := 0 to pd_max do pd.ray[i] := 0; for i := 0 to uda_max do uda[i] := 0; pd.prior := priority; for i := 1 to 8 do begin pd.name[i] := name[i]; pd.name2[i] := name[i] end; p.puda := addr(uda); pd.uda := shr(p.off, 4); {make into paragraph address} fix_stack(task, uda, size); if create_process(pd) then writeln('Starting ', name) else writeln('Startup of ', name, ' failed'); end; function makeq(var qd: qd_type; {queue descriptor address} var qpb: qpb_type; {queue parm block address} name: name_type; {name of queue} msglen: integer; {length of message in bytes} nmsgs: integer) {max messages in queue} : boolean; begin {make and open the main message queue} qd.z1 := #0; {initialize queue descriptor} qd.flags := 0; qd.name := name; qd.msglen := msglen; qd.nmsgs := nmsgs; qd.z2 := #0; qd.z3 := #0; qd.z4 := 0; if not queue_make(qd) then begin writeln('Unable to make queue'); makeq := false end else begin qpb.z := 0; {initialize queue parameter block} qpb.name := name; if not queue_oper(q_open, qpb) then begin writeln('Unable to open queue'); makeq := false end else makeq := true; end end; function read_msg(rm_qpb: qpb_type; {local copy of the q parm block} var msgp: qd_msg) {where to send the message} : boolean; var p: pointer; rm_msg: qd_msg; {local copy of message read} begin {read a message from a queue} rm_qpb.nmsgs := 1; p.pqdm := addr(rm_msg); rm_qpb.buffer := p.off; {put offset of msg into qpb} read_msg := queue_oper(q_read, rm_qpb); msgp := rm_msg; {copy message to output} end; function write_msg(wm_qpb: qpb_type; {local copy of the q parm block} wm_msg: qd_msg) {local copy of the message} : boolean; var p: pointer; begin {write a message to a queue} wm_qpb.nmsgs := 1; p.pqdm := addr(wm_msg); wm_qpb.buffer := p.off; {put offset of msg into qpb} write_msg := queue_oper(q_write, wm_qpb); end; procedure task_a; var msg_a: qd_msg; begin msg_a.count := 0; msg_a.name := 'A-msg '; repeat delay(31); msg_a.count := msg_a.count + 1; if not write_msg(qpb, msg_a) then msg_a.count := 999; until msg_a.count >= 9; done_a := true; terminate; end; procedure task_b; var msg_b: qd_msg; begin msg_b.count := 0; msg_b.name := ' B-msg '; repeat delay(19); msg_b.count := msg_b.count + 1; if not write_msg(qpb, msg_b) then msg_b.count := 999; until msg_b.count >= 9; done_b := true; terminate; end; procedure task_c; var msg_c: qd_msg; begin msg_c.count := 0; msg_c.name := ' C-msg '; repeat delay(25); msg_c.count := msg_c.count + 1; if not write_msg(qpb, msg_c) then msg_c.count := 999; until msg_c.count >= 9; done_c := true; terminate; end; begin {main program} if not makeq(qd, qpb, 'MAIN QQQ', sizeof(qmsg), qd_nmsgs) then exit; if not set_priority(def_prior) then begin writeln('Unable to set main program priority'); exit end; done_a := false; done_b := false; done_c := false; writ_a := false; writ_b := false; writ_c := false; init_mpm_util(1500); startup(pd_a, uda_a, addr(task_a), 'TASK_A ', def_prior, 1500); startup(pd_b, uda_b, addr(task_b), 'TASK_B ', def_prior, 1500); startup(pd_c, uda_c, addr(task_c), 'TASK_C ', def_prior, 1500); delay(1); repeat if not readmsg(qpb, qmsg) then begin writeln('Error trying to read queue'); exit; end; writeln(qmsg.name, ' loop count = ', qmsg.count); if done_a then begin writeln('TASK A completed'); writ_a := true; done_a := false; end; if done_b then begin writeln('TASK B completed'); writ_b := true; done_b := false; end; if done_c then begin writeln('TASK C completed'); writ_c := true; done_c := false; end; until writ_a and writ_b and writ_c; if not queue_oper(q_delete, qpb) then writeln('Unable to delete queue'); end.