/* * ASYNCOP.C */ typedef unsigned char ubyte; typedef unsigned short uword; typedef unsigned long ulong; typedef struct Message MSG; typedef struct MsgPort PORT; typedef struct Task TASK; typedef struct Node NODE; #define ASYMSG struct _ASYMSG #define ASYHAN struct _ASYHAN ASYMSG { MSG msg; void (*func)(); long arg1; long arg2; long arg3; }; ASYHAN { PORT *rport; /* Reply Port */ PORT *port; /* Send Port */ long acount; /* Messages Sent */ long ccount; /* Messages Replied*/ long a4,a5; /* A4 and A5 */ }; extern TASK *CreateTask(); extern TASK *FindTask(); extern PORT *CreatePort(); extern void *AllocMem(); extern void *GetMsg(); extern void asyhandler(); extern void nop(); ASYHAN * NewAsyncOp() { register TASK *task; register TASK *mytask = FindTask(NULL); register ASYHAN *as = AllocMem(sizeof(ASYHAN), MEMF_CLEAR|MEMF_PUBLIC); ASYMSG StartupMsg; as->rport = CreatePort(NULL, 0); PutA4A5(&as->a4); task = CreateTask("async.task", mytask->tc_Node.ln_Pri + 1, asyhandler, 4096); task->tc_UserData = (APTR)as; Signal(task, SIGBREAKF_CTRL_F); Wait(1 << as->rport->mp_SigBit); return(as); } StartAsyncOp(as, func, arg1, arg2, arg3) register ASYHAN *as; void (*func)(); { register ASYMSG *am = GetMsg(as->rport); /* Free Msg List */ if (!am) { am = AllocMem(sizeof(ASYMSG), MEMF_PUBLIC|MEMF_CLEAR); am->msg.mn_ReplyPort = as->rport; } am->func = func; am->arg1 = arg1; am->arg2 = arg2; am->arg3 = arg3; ++as->acount; PutMsg(as->port, am); } CheckAsyncOp(as, n) register ASYHAN *as; unsigned long n; { if (n > as->acount) n = as->acount; return(n <= as->ccount); } /* * acount = #messages sent * ccount = #messages replied */ WaitAsyncOp(as, n) register ASYHAN *as; unsigned long n; { if (n > as->acount) n = as->acount; while (n > as->ccount) Wait(1 << as->rport->mp_SigBit); Forbid(); as->ccount -= n; Permit(); as->acount -= n; } CloseAsyncOp(as) register ASYHAN *as; { ASYMSG EndMsg; ASYMSG *am; WaitAsyncOp(as, -1); /* Wait for all operations to complete */ while (am = GetMsg(as->rport)) /* Free any messages */ FreeMem(am, sizeof(ASYMSG)); EndMsg.func = NULL; EndMsg.msg.mn_ReplyPort = as->rport; PutMsg(as->port, &EndMsg); WaitPort(as->rport); GetMsg(as->rport); DeletePort(as->rport); FreeMem(as, sizeof(*as)); } static void asyhandler() { register ASYHAN *as; register ASYMSG *am; Wait(SIGBREAKF_CTRL_F); as = (ASYHAN *)FindTask(NULL)->tc_UserData; as->port = CreatePort(NULL, 0); Signal(as->rport->mp_SigTask, 1 << as->rport->mp_SigBit); for (;;) { WaitPort(as->port); am = GetMsg(as->port); if (!am->func) break; CallAMFunc(&as->a4, &am->func); ++as->ccount; ReplyMsg(am); } DeletePort(as->port); as->port = NULL; Forbid(); ReplyMsg(am); } #asm ; ; load the lw array ptr with a4 & a5 _PutA4A5: move.l 4(sp),A0 move.l A4,(A0)+ move.l A5,(A0)+ rts _CallAMFunc: move.l 4(sp),A0 ; &a4,a5 move.l 8(sp),A1 ; &func,arg1,arg2,arg3 movem.l D2/D3/A4/A5/A6,-(sp) move.l (A0)+,A4 move.l (A0)+,A5 move.l 12(A1),-(sp) move.l 8(A1),-(sp) move.l 4(A1),-(sp) move.l (A1),A1 jsr (A1) add.w #12,sp movem.l (sp)+,D2/D3/A4/A5/A6 rts #endasm