diff options
author | Chris Young <chris@unsatisfactorysoftware.co.uk> | 2014-11-22 16:24:26 +0000 |
---|---|---|
committer | Chris Young <chris@unsatisfactorysoftware.co.uk> | 2014-11-22 16:27:39 +0000 |
commit | 2de1553a002aff7fa89bb466cdba1b3414413901 (patch) | |
tree | 2ad599d6f20e8280036b6d464d070fdeb1359071 /amiga/schedule.c | |
parent | f8d8d218d8d5f7fdeb2edc0c5fa3f0a22e6d5a1b (diff) | |
download | netsurf-2de1553a002aff7fa89bb466cdba1b3414413901.tar.gz netsurf-2de1553a002aff7fa89bb466cdba1b3414413901.tar.bz2 |
New scheduler
Diffstat (limited to 'amiga/schedule.c')
-rwxr-xr-x | amiga/schedule.c | 179 |
1 files changed, 152 insertions, 27 deletions
diff --git a/amiga/schedule.c b/amiga/schedule.c index fa6de688d..607c3d8e5 100755 --- a/amiga/schedule.c +++ b/amiga/schedule.c @@ -18,6 +18,7 @@ #include "amiga/os3support.h" +#include <proto/dos.h> #include <proto/exec.h> #include <proto/timer.h> @@ -26,9 +27,11 @@ #include <pbl.h> #include "utils/errors.h" +#include "utils/log.h" #include "amiga/schedule.h" +static struct MsgPort *smsgport = NULL; /* to send messages for the scheduler to */ static struct TimeRequest *tioreq; struct Device *TimerBase; struct TimerIFace *ITimer; @@ -44,11 +47,14 @@ struct nscallback struct ami_schedule_message { struct Message msg; int type; - struct nscallback *nscb; -} + int t; + void *callback; + void *p; +}; enum { AMI_S_SCHEDULE = 0, + AMI_S_RUN, AMI_S_STARTUP, AMI_S_EXIT }; @@ -217,13 +223,35 @@ static int ami_schedule_compare(const void *prev, const void *next) } -/* exported function documented in amiga/schedule.h */ -void schedule_run(void) +/** + * Process events up to current time. + * NetSurf entry point after being signalled by the scheduler process. + */ +static void schedule_run(struct ami_schedule_message *asmsg) +{ + void (*callback)(void *p) = asmsg->callback; + void *p = asmsg->p; + + callback(p); +} + +/** + * Process events up to current time. + * + * This implementation only takes the top entry off the heap, it does not + * venture to later scheduled events until the next time it is called - + * immediately afterwards, if we're in a timer signalled loop. + */ +static void ami_scheduler_run(struct MsgPort *nsmsgport) { struct nscallback *nscb; void (*callback)(void *p); void *p; + struct ami_schedule_message *asmsg = AllocSysObjectTags(ASOT_MESSAGE, + ASOMSG_Size, sizeof(struct ami_schedule_message), + TAG_END); + nscb = pblHeapGetFirst(schedule_list); if(nscb == -1) return; @@ -232,9 +260,17 @@ void schedule_run(void) ami_schedule_remove_timer_event(nscb); pblHeapRemoveFirst(schedule_list); FreeVec(nscb); - callback(p); + + asmsg->type = AMI_S_RUN; + asmsg->callback = callback; + asmsg->p = p; + + PutMsg(nsmsgport, (struct Message *)asmsg); + + return; } + static struct MsgPort *ami_schedule_open_timer(void) { struct MsgPort *msgport = AllocSysObjectTags(ASOT_PORT, @@ -268,7 +304,7 @@ static void ami_schedule_close_timer(struct MsgPort *msgport) * * /return true if initialised ok or false on error. */ -struct MsgPort *ami_schedule_create(void) +static struct MsgPort *ami_schedule_create(void) { struct MsgPort *msgport = ami_schedule_open_timer(); schedule_list = pblHeapNew(); @@ -283,7 +319,7 @@ struct MsgPort *ami_schedule_create(void) * Finalise amiga scheduler * */ -void ami_schedule_free(struct MsgPort *msgport) +static void ami_schedule_free(struct MsgPort *msgport) { schedule_remove_all(); pblHeapFree(schedule_list); // this should be empty at this point @@ -295,40 +331,86 @@ void ami_schedule_free(struct MsgPort *msgport) /* exported function documented in amiga/schedule.h */ nserror ami_schedule(int t, void (*callback)(void *p), void *p) { + if(smsgport == NULL) return NSERROR_INIT_FAILED; + + struct ami_schedule_message *asmsg = AllocSysObjectTags(ASOT_MESSAGE, + ASOMSG_Size, sizeof(struct ami_schedule_message), + TAG_END); + + asmsg->type = AMI_S_SCHEDULE; + asmsg->t = t; + asmsg->callback = callback; + asmsg->p = p; + + PutMsg(smsgport, (struct Message *)asmsg); + + return NSERROR_OK; +} + +static nserror ami_scheduler_schedule(struct ami_schedule_message *asmsg) +{ struct nscallback *nscb; if(schedule_list == NULL) return NSERROR_INIT_FAILED; - if (t < 0) return schedule_remove(callback, p); - - if ((nscb = ami_schedule_locate(callback, p, false))) { - return ami_schedule_reschedule(nscb, t); + if (asmsg->t < 0) return schedule_remove(asmsg->callback, asmsg->p); + + if ((nscb = ami_schedule_locate(asmsg->callback, asmsg->p, false))) { + return ami_schedule_reschedule(nscb, asmsg->t); } nscb = AllocVecTagList(sizeof(struct nscallback), NULL); if(!nscb) return NSERROR_NOMEM; - if (ami_schedule_add_timer_event(nscb, t) != NSERROR_OK) + if (ami_schedule_add_timer_event(nscb, asmsg->t) != NSERROR_OK) return NSERROR_NOMEM; - nscb->callback = callback; - nscb->p = p; + nscb->callback = asmsg->callback; + nscb->p = asmsg->p; pblHeapInsert(schedule_list, nscb); return NSERROR_OK; } +/* exported interface documented in amiga/schedule.h */ +void ami_schedule_handle(struct MsgPort *nsmsgport) +{ + /* nsmsgport is the NetSurf message port that the + * scheduler task is sending messages to. */ + struct ami_schedule_message *asmsg; + + while((asmsg = (struct ami_schedule_message *)GetMsg(nsmsgport))) { + if(asmsg->msg.mn_Node.ln_Type == NT_REPLYMSG) { + /* if it's a reply, free stuff */ + FreeSysObject(ASOT_MESSAGE, asmsg); + } else { + switch(asmsg->type) { + case AMI_S_STARTUP: + smsgport = asmsg->msg.mn_ReplyPort; + break; + + case AMI_S_RUN: + schedule_run(asmsg); + break; + + default: + // unknown message + break; + } + FreeSysObject(ASOT_MESSAGE, asmsg); /* don't reply, just free */ + } + } +} static int32 ami_scheduler_process(STRPTR args, int32 length, APTR execbase) { struct Process *proc = (struct Process *)FindTask(NULL); struct MsgPort *nsmsgport = proc->pr_Task.tc_UserData; - struct MsgPort *schedulermsgport = IExec->AllocSysObjectTags(ASOT_PORT, TAG_END); + struct MsgPort *schedulermsgport = AllocSysObjectTags(ASOT_PORT, TAG_END); struct MsgPort *timermsgport = ami_schedule_create(); bool running = true; struct TimerRequest *timermsg = NULL; - struct ami_schedule_message *schedulemsg = NULL; ULONG schedulesig = 1L << schedulermsgport->mp_SigBit; ULONG timersig = 1L << timermsgport->mp_SigBit; uint32 signalmask = schedulesig | timersig; @@ -337,13 +419,13 @@ static int32 ami_scheduler_process(STRPTR args, int32 length, APTR execbase) /* Send a startup message to the message port we were given when we were created. * This tells NetSurf where to send scheduler events to. */ - struct ami_schedule_message *asmsg = IExec->AllocSysObjectTags(ASOT_MESSAGE, + struct ami_schedule_message *asmsg = AllocSysObjectTags(ASOT_MESSAGE, ASOMSG_Size, sizeof(struct ami_schedule_message), ASOMSG_ReplyPort, schedulermsgport, TAG_END); - asmsg.type = AMI_S_STARTUP; - PutMsg(nsmsgport, asmsg); + asmsg->type = AMI_S_STARTUP; + PutMsg(nsmsgport, (struct Message *)asmsg); /* Main loop for this process */ @@ -352,18 +434,32 @@ static int32 ami_scheduler_process(STRPTR args, int32 length, APTR execbase) if(signal & timersig) { while((timermsg = (struct TimerRequest *)GetMsg(timermsgport))) { - schedule_run(); /* \todo get top scheduled event and signal nsmsgport to run the callback */ - ReplyMsg((struct Message *)timermsg); + ami_scheduler_run(nsmsgport); + //ReplyMsg((struct Message *)timermsg); /* \todo why does this crash? */ } } if(signal & schedulesig) { while((asmsg = (struct ami_schedule_message *)GetMsg(schedulermsgport))) { - /* \todo if it's a reply, free stuff - if(asmsg->nscb) FreeVec(asmg->nscb); - FreeSysObject(ASOT_Message, asmsg); - */ - //ReplyMsg((struct Message *)asmsg); + if(asmsg->msg.mn_Node.ln_Type == NT_REPLYMSG) { + /* if it's a reply, free stuff */ + FreeSysObject(ASOT_MESSAGE, asmsg); + } else { + switch(asmsg->type) { + case AMI_S_SCHEDULE: + ami_scheduler_schedule(asmsg); + break; + + case AMI_S_EXIT: + running = false; + break; + + default: + // unknown message + break; + } + FreeSysObject(ASOT_MESSAGE, asmsg); /* don't reply, just free */ + } } } } @@ -382,9 +478,11 @@ static int32 ami_scheduler_process(STRPTR args, int32 length, APTR execbase) */ nserror ami_scheduler_process_create(struct MsgPort *nsmsgport) { + if(nsmsgport == NULL) return NSERROR_INIT_FAILED; + struct Process *proc = CreateNewProcTags( NP_Name, "NetSurf scheduler", - NP_Entry, ami_schedule_process, + NP_Entry, ami_scheduler_process, NP_Child, TRUE, NP_StackSize, 16384, NP_Priority, 1, @@ -395,6 +493,33 @@ nserror ami_scheduler_process_create(struct MsgPort *nsmsgport) return NSERROR_NOMEM; } + LOG(("Waiting for scheduler process to start up...")); + + WaitPort(nsmsgport); + struct ami_schedule_message *asmsg = (struct ami_schedule_message *)GetMsg(nsmsgport); + + if(asmsg->type == AMI_S_STARTUP) { /* We shouldn't get any other messages at this stage */ + smsgport = asmsg->msg.mn_ReplyPort; + ReplyMsg((struct Message *)asmsg); + } + + LOG(("Scheduler started")); + return NSERROR_OK; } +/* exported function documented in amiga/schedule.h */ +void ami_scheduler_process_delete(void) +{ + if(smsgport == NULL) return; + + struct ami_schedule_message *asmsg = AllocSysObjectTags(ASOT_MESSAGE, + ASOMSG_Size, sizeof(struct ami_schedule_message), + TAG_END); + + asmsg->type = AMI_S_EXIT; + PutMsg(smsgport, (struct Message *)asmsg); + + return; +} + |