;**************************************************************** ;* * ;* Queue system subroutines: Q System must be owned * ;* before calling any of the following routines * ;* * ;**************************************************************** queverify: ; check QLR for existence of QD address ;--------- --------------------------------------- ; entry: U_WRKSEG:DX = offset of QPB ; exit: CX = 0 if queue is found ; CX = E_NO_QUEUE error code, if not ; BX=SI=QD offset ; ES,DX preserved push es ;save UDA mov es,u_wrkseg mov bx,dx ;ES:BX->QPB mov bx,es:qpb_qaddr[bx] ;get QD from user's QPB pop es ;restore UDA lea si,qlr-q_link qv_nxt: mov si,q_link[si] ;SI addresses of valid QDs test si,si ! jz qv_nqf cmp bx,si ! jne qv_nxt xor cx,cx ! ret ;BX=SI=QD offset, return success qv_nqf: mov cx,e_no_queue ;couldn't find the queue ret getqdaddr: ;---------- ; entry: DX = offset of QD in U_WRKSEG ; exit: DI = offset of QD in SYSDAT ; ; If QD address is within SYSDAT use it. ; Else get a QD from QDUL and set QF_TABLE flag. ; If Q_NMSGS=0 in QD then return error. ; If 0 length buffer needed, zero the Q_BUF field. ; If buffer space is within SYSDAT use it. Else get buffer ; from QMAU. Return the QD address within SYSDAT. push dx ;save QD offset mov bx,qdlen call sysdat_chk jcxz g_qul ;CX=0 if not within SYSDAT mov ax,u_wrkseg ;# of paragraphs to U_WRKSEG mov bx,ds sub ax,bx ;from SYSDAT mov cl,4 ! shl ax,cl ;make into # of bytes pop di ;DI=QD in U_WRKSEG add di,ax ;make QD relative to SYSDAT jmps g_qd g_qul: mov di,qul ;get QD from QUL test di,di ;DI=unused QD jnz g_gotqd pop dx mov cx,e_no_qd ;no QD available ret g_gotqd: mov ax,q_link[di] mov qul,ax pop si ;SI=QD in U_WRKSEG push di ;save SYSDAT QD mov cx,qdlen/2 ; ES=UDA, DS=SYSDAT mov ax,ds mov ds,u_wrkseg ; DS:SI = QD in U_WRKSEG push es ! mov es,ax ; ES:DI = QD in SYSDAT rep movsw ; copy QD into QD in SYSDAT mov ax,es ! mov ds,ax pop es ; ES=UDA, DS=SYSDAT pop di ; SYSDAT:DI -> New QD or q_flags[di],qf_table ; Set "from table" flag g_qd: ;DI=QD in SYSDAT xor cx,cx ;CX=0 cmp q_nmsgs[di],cx ;must have one or more msgs jne g_buflen ;or illegal queue mov cx,e_no_qbuf jmps g_qdfree g_buflen: ;if MX or buffer length is zero test q_flags[di],qf_mx ;0 Q_BUF field and return jnz g_mx ;CX=0 to indicate success cmp q_msglen[di],cx jne g_getbuf g_mx: mov q_buf[di],cx ret g_getbuf: ;non 0 length buffer needed cmp q_buf[di],0 ;is there a buffer specified? je g_buf mov ax,q_msglen[di] ;yes make sure it fits in SYSDAT mul q_nmsgs[di] ;AX=needed buffer space mov bx,ax mov dx,q_buf[di] call sysdat_chk jcxz g_buf ;CX=0 not within SYSDAT mov ax,u_wrkseg ;# of paragraphs to U_WRKSEG mov bx,ds sub ax,bx ;from SYSDAT mov cl,4 ! shl ax,cl ;make into # of bytes add q_buf[di],ax ;make buffer relative to SYSDAT xor cx,cx ;indicate success ret g_buf: ;allocate buffer space to queue call qspace jcxz g_ret mov cx,e_no_qbuf ;no buffer space g_qdfree: mov ax,qul ;error return QD to QUL mov q_link[di],ax mov qul,di ;CX = error code g_ret: ret sysdat_chk: ;---------- ; entry: DX = offset of data structure to check ; relative to U_WRKSEG ; BX = length of data structure ; exit: CX <> 0 if within SYSDAT ; or wrap around ; CX = 0 if not within SYSDAT ; SI,DI preserved ; Check data structure for being within SYSDAT ; Also check that data structure doesn't wrap ; around at 64K, or 1 megabyte. add dx,bx ;find end of data structure jc sc_no ;check for 64K wrap around add dx,0fh mov cl,4 ;round up to next paragraph shr dx,cl ;1st paragraph after struct relative add dx,u_wrkseg ;to U_WRKSEG jc sc_no ;next paragraph after struct ;check for 1 MB wrap around mov ax,sysdat cmp dx,ax ;check for below SYSDAT jb sc_no add ax,1000h ;check for above SYSDAT cmp ax,endseg ;must be within 64k and ENDSEG jb sc_end ;(use the smaller of the 2) mov ax,endseg sc_end: cmp dx,ax ;DX=next paragraph, ja sc_no mov cl,1 ;indicate within SYSDAT ret sc_no: xor cx,cx ret qspace: ;------ ; entry: DI = QD address ; exit: CX = 0 if ok else error code ; DI preserved ; Allocate buffer space for QD ; The QMAU describes the Memory Allocation Unit ; for the queues. QMAU is set up by GENCCPM or GENSYS. mov ax,q_msglen[di] ;compute size of buffer mul q_nmsgs[di] ;AX=size of request xor cx,cx push cx ! push cx ! push ax ;call MALLOC push ax ! push cx ;with MPB on stack mov dx,sp ! mov ax,ss mov ds,ax mov bx,offset qmau push di ;save QD mov cx,f_maualloc ;go through OSIF to call osif ;get U_WRKSEG=SS pop di ;DI=QD mov ds,sysdat cmp cx,0 ! jne qspace_ret mov bp,sp mov ax,mpb_start[bp] mov q_buf[di],ax ;address of buffer qspace_ret: add sp,10 ;pop MPB from stack ret remqd: ;----- ; Place QD on queue unused list ; entry: DS:DI = QD address ; exit: none mov ax,q_flags[di] and ax,qf_table ! jz rqd_exit mov ax,qul ! mov q_link[di],ax mov qul,di jmps qrelease rqd_exit: ret qrelease: ;-------- ; entry: DI = QD address ; exit : none ; ; Release buffer space for QD. ; If the released space is ajacent to another ; free area, they are joined in the SAT table. ; The QMAU describes the Memory Allocation Unit ; for the queues. QMAU is set up by GENCCPM or GENSYS. mov ax,q_buf[di] mov cx,offset qmau push ax ! push ax ! push cx ;MFPB on stack mov cx,f_maufree mov dx,sp ! mov ax,ss ! mov ds,ax call osif add sp,6 ;pop MFPB from stack mov ds,cs:sysdat ;DS=SYSDAT ret