.title Message Facility for Clients .sbttl cldrvr.mac ; These message passing routines uses the TSX+ named ; message channel facility. ; ; The message channel name is derived from the ; current job number and is thus always unique. ; ; The xmit channel is always to the TCPIP channel. ; ; The maximum message length supported by these ; routines is 16 bytes. .mcall .rsum .page .sbttl cldrvr initialization ; ; VOID cl_init(); ; ; this routine should be called before ; any messages are sent or recieved ; to setup the return message uid. ; .psect c$code cl.init:: mov #gval,r0 ;.gval for jobnum emt 375 mov r0,jobnum ;save real number mov #"00,userid+4 ;preset id 1$: cmpb #10.,r0 ;build number bhi 2$ add #246.,r0 ;low byte is lsd br 1$ ;high byte is msd 2$: swab r0 add r0,userid+4 jsr pc,cl.recv ;activate message handler and ;discard all pending messages 3$: mov #tmwait,r0 ;.twait emt 375 jsr pc,cl.recv ;get message bne 3$ ;loop until no messages mov jobnum,r0 ;return the job number rts pc .psect c$data gval: .byte 0,34 ;.gval .word -2 ;job number .page .sbttl Receive Message Routine ; ; (MSGPKT *) cl_recv() ; ; Returns a pointer to a received message ; .psect c$code cl.recv:: clr -(sp) ;default to no message tst quecnt ;data ? beq 1$ ;no - skip mov outpos,r1 ;message index ash #4,r1 ;offset into data queue add #datque,r1 ;buffer address mov #rcvmsg,r0 ;received message mov r0,(sp) mov (r1)+,(r0)+ ;copy message mov (r1)+,(r0)+ mov (r1)+,(r0)+ mov (r1)+,(r0)+ mov (r1)+,(r0)+ mov (r1)+,(r0)+ mov (r1)+,(r0)+ mov (r1)+,(r0)+ mov outpos,r1 ;next message buffer inc r1 bic #^C17,r1 ;ring buffer mov r1,outpos dec quecnt ;one more message has been read 1$: tst active ;message facility active ? bne 2$ ;yes - exit jsr pc,cmpltn ;activate 2$: mov (sp)+,r0 ;return a NULL / POINTER rts pc .page .sbttl Completion Processing ; ; Message received completion routine ; ; This proceedure verifies that the incoming ; message is unique. Non unique messages are ; discarded here to improve overall efficiency ; of the messaging services for the client. .psect c$code cmpltn: tst active ;active ? beq 2$ ;no - just activate tst re.spnd bgt 1$ .rsum ;resume any suspension inc re.spnd 1$: jsr pc,unique ;check for unique entry 2$: clr active ;temporarily inactive cmp quecnt,#12. ;space for another message ? bhis 3$ ;no - exit mov #1,active ;activated mov #msgact,r0 ;msgact argument block mov inppos,r1 ash #4,r1 ;offset into data queue add #datque,r1 ;buffer address mov r1,4(r0) ;load argument block emt 375 3$: rts pc unique: mov inppos,r0 ;any messages in buffer ? mov outpos,r1 cmp r0,r1 beq 4$ ;no - then add this one jsr pc,6$ ;else - prepare to check uniqueness mov r0,r5 ;compute newest elements address ash #4,r5 add #datque,r5 1$: mov r5,r2 ;newest elements address mov r1,r3 ;compute old element address ash #4,r3 add #datque,r3 mov #8.,r4 ;16-bytes 2 at a time 2$: cmp (r2)+,(r3)+ ;compare for unique entry bne 3$ sob r4,2$ br 5$ ;not a unique entry 3$: inc r1 ;next queued element bic #^C17,r1 cmp r1,r0 ;check all queued messages bne 1$ 4$: inc r0 ;next message buffer bic #^C17,r0 ;ring buffer mov r0,inppos inc quecnt ;one more unique message has arrived 5$: rts pc 6$: mov r2,-(sp) ; save registers r2-r5 mov r3,-(sp) mov r4,-(sp) mov r5,-(sp) mov 10(sp),-(sp) ; stack return jsr pc,@(sp)+ ; call return as a coroutine mov (sp)+,r5 ; on return restore r2-r5 mov (sp)+,r4 mov (sp)+,r3 mov (sp)+,r2 tst (sp)+ ; pop used return rts pc ; and exit .psect c$data msgact: .byte 1,106 ;message input with completion .word userid .word datque .word 16. ;maximum message size .word cmpltn ;completion routine active: .word 0 ;message handler active flag inppos: .word 0 ;position for arriving message outpos: .word 0 ;position for next readout quecnt: .word 0 ;number of messages in datque datque: .blkb 256. ;16 - 16-byte message buffers rcvmsg: .blkb 16. ;message read from buffer userid: .ascii /USER00/ ;my message channel .word 0 ;two null characters jobnum: .word 0 ;my job number class: .word 0 ;message class event: .word 0 ;message event data: .word 0 ;message data .page .sbttl Transmit Message Routine ; ; int cl_xmit(class,event,data) ; ; sends a message to TCPIP ; ; ; A potential deadlock may occur if the internal ; message buffer becomes full and the system ; message buffers are all in use. An attempt to ; prevent this is done by limiting the cl_recv ; completion routine to 12. entries before going ; inactive. The sv_xmit routine may then attempt ; to get a message for cl_recv and then immediately ; send its own message. This proceedure will allow ; the sending of a message if a message was pending ; for cl_recv. If this proceedure fails then ; cl_xmit enters a wait loop to try retransmission ; after a suitable delay. .psect c$code cl.xmit:: jsr r5,csv$ ; move data into position mov c$pmtr+0(r5),class ;message class mov c$pmtr+2(r5),event ;message event mov c$pmtr+4(r5),data ;message data 1$: mov #msgxmt,r0 ;send message emt 375 bcc 3$ ;ok - skip tst active ;completion active ? bne 2$ ;yes - just wait cmp quecnt,#16. ;any room for another message ? bhis 2$ ;no - just wait mov #msgrcv,r0 ;msgrcv argument block mov inppos,r1 ash #4,r1 ;offset into data queue add #datque,r1 ;buffer address mov r1,4(r0) ;load argument block emt 375 bcs 2$ ;no message - just wait jsr pc,unique ;check for unique message br 1$ ;and try to send our message again 2$: mov #tmwait,r0 ;.twait emt 375 br 1$ ;retry sending message 3$: clr r0 ;sent jmp cret$ .psect c$data msgxmt: .byte 0,104 ;message output .word dstid ;destination .word userid ;message .word 16. ;message length msgrcv: .byte 0,105 ;message input with continuation .word userid .word datque .word 16. tmwait: .byte 0,24 ;.twait .word 1$ 1$: .word 0,3 ;3-tick wait dstid: .ascii /TCPIP / ;destination message channel .end