.title Message Facility for Servers .sbttl svdrvr.mac ; These message passing routines uses the TSX+ named ; message channel facility. ; ; The xmit message channel name is derived from the ; requestors job number and is thus always unique. ; ; The receive channel is named TCPIP. ; ; The maximum message length supported by these ; routines is 16 bytes. .mcall .rsum .page .sbttl svdrvr initialization .psect c$code ; ; VOID sv_init(); ; ; Initialize the svdrvr ; sv.init:: jsr r5,csv$ mov #32.,r2 mov #msgrcv,r1 ;argument block mov #userid,2(r1) 1$: mov r1,r0 ;discard all pending messages emt 375 ;for USERxx bcc 1$ incb userid+5 cmpb #'9,userid+5 bhis 2$ movb #'0,userid+5 incb userid+4 2$: dec r2 bge 1$ mov #msgrcv,r1 ;argument block mov #tcpid,2(r1) 3$: mov r1,r0 ;discard all pending messages emt 375 ;for TCPIP bcc 3$ mov #gval,r0 ;.gval for jobnum emt 375 mov r0,jobnum ;save real number jmp cret$ .psect c$data gval: .byte 0,34 ;.gval .word -2 ;job number .page .sbttl Receive Message Routine ; ; (MSGPKT *) sv_recv() ; ; Returns a pointer to a received message ; .psect c$code sv.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 server. .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 tcpid .word datque .word 16. .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 tcpid: .ascii /TCPIP / ;my message channel name .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 sv_xmit(jobnum,class,event,data) ; ; sends a message to selected job ; ; ; 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 sv_recv ; completion routine to 12. entries before going ; inactive. The sv_xmit routine may then attempt ; to get a message for sv_recv and then immediately ; send its own message. This proceedure will allow ; the sending of a message if a message was pending ; for sv_recv. If this proceedure fails then ; sv_xmit enters a wait loop to try retransmission ; after a suitable delay. .psect c$code sv.xmit:: jsr r5,csv$ mov c$pmtr(r5),r0 ;job number ble 6$ ;0 or negative jobs - exit cmp r0,#32. ;bound the number bhis 6$ ;out of range - exit ; build user name mov #"00,userid+4 ;initialize the user 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 ; move data into position mov c$pmtr+2(r5),class ;message class mov c$pmtr+4(r5),event ;message event mov c$pmtr+6(r5),data ;message data 3$: mov #msgxmt,r0 ;send message emt 375 bcc 5$ ;ok - skip tst active ;completion active ? bne 4$ ;yes - just wait cmp quecnt,#16. ;any room for another message ? bhis 4$ ;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 4$ ;no message - just wait jsr pc,unique ;check for unique message br 3$ ;and try to send our message again 4$: mov #tmwait,r0 ;.twait emt 375 br 3$ ;retry sending message 5$: clr r0 ;sent jmp cret$ 6$: mov #-1,r0 ;error jmp cret$ .psect c$data msgxmt: .byte 0,104 ;message output .word userid ;destination .word tcpid ;outgoing message .word 16. msgrcv: .byte 0,105 ;message input with continuation .word tcpid .word datque .word 16. tmwait: .byte 0,24 ;.twait .word 1$ 1$: .word 0,3 ;3-tick wait userid: .ascii /USER00/ ;destination message channel .end