summaryrefslogtreecommitdiff
path: root/amiga
diff options
context:
space:
mode:
authorChris Young <chris@unsatisfactorysoftware.co.uk>2014-11-22 16:30:43 +0000
committerChris Young <chris@unsatisfactorysoftware.co.uk>2014-11-22 16:30:43 +0000
commit186e1f4ee32c518a599038e15e4b209864478db7 (patch)
tree2ad599d6f20e8280036b6d464d070fdeb1359071 /amiga
parentfe567952057e820b040371be639842fcb2317bf2 (diff)
parent2de1553a002aff7fa89bb466cdba1b3414413901 (diff)
downloadnetsurf-186e1f4ee32c518a599038e15e4b209864478db7.tar.gz
netsurf-186e1f4ee32c518a599038e15e4b209864478db7.tar.bz2
New asynchronous scheduler
This ensures that if other processes other than the main NetSurf process try to create scheduled tasks, they are always run on the main process.
Diffstat (limited to 'amiga')
-rw-r--r--amiga/gui.c44
-rwxr-xr-xamiga/schedule.c278
-rwxr-xr-xamiga/schedule.h30
3 files changed, 286 insertions, 66 deletions
diff --git a/amiga/gui.c b/amiga/gui.c
index e76a01e66..461a20dab 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -167,6 +167,7 @@ struct ami_gui_tb_userdata {
int items;
};
+static struct MsgPort *schedulermsgport = NULL;
static struct MsgPort *appport;
static Class *urlStringClass;
@@ -416,7 +417,9 @@ static bool ami_open_resources(void)
ASO_NoTrack, FALSE,
TAG_DONE))) return false;
- ami_file_req_init();
+ if(!(schedulermsgport = AllocSysObjectTags(ASOT_PORT,
+ ASO_NoTrack, FALSE,
+ TAG_DONE))) return false;
return true;
}
@@ -2689,12 +2692,11 @@ void ami_get_msg(void)
{
ULONG winsignal = 1L << sport->mp_SigBit;
ULONG appsig = 1L << appport->mp_SigBit;
- ULONG schedulesig = 1L << msgport->mp_SigBit;
+ ULONG schedulesig = 1L << schedulermsgport->mp_SigBit;
ULONG ctrlcsig = SIGBREAKF_CTRL_C;
uint32 signal = 0;
fd_set read_fd_set, write_fd_set, except_fd_set;
int max_fd = -1;
- struct TimerRequest *timermsg = NULL;
struct MsgPort *printmsgport = ami_print_get_msgport();
ULONG printsig = 0;
ULONG helpsignal = ami_help_signal();
@@ -2743,10 +2745,7 @@ void ami_get_msg(void)
}
if(signal & schedulesig) {
- if((timermsg = (struct TimerRequest *)GetMsg(msgport))) {
- ReplyMsg((struct Message *)timermsg);
- schedule_run();
- }
+ ami_schedule_handle(schedulermsgport);
}
if(signal & helpsignal)
@@ -2994,17 +2993,17 @@ static void gui_quit(void)
ami_mouse_pointers_free();
LOG(("Freeing clipboard"));
ami_clipboard_free();
+ LOG(("Removing scheduler process"));
+ ami_scheduler_process_delete();
- FreeSysObject(ASOT_PORT,appport);
- FreeSysObject(ASOT_PORT,sport);
+ FreeSysObject(ASOT_PORT, appport);
+ FreeSysObject(ASOT_PORT, sport);
+ FreeSysObject(ASOT_PORT, schedulermsgport);
ami_file_req_free();
ami_openurl_close();
FreeStringClass(urlStringClass);
- LOG(("Freeing scheduler"));
- ami_schedule_free();
-
FreeObjList(window_list);
FreeVec(current_user_options);
@@ -5348,6 +5347,16 @@ int main(int argc, char** argv)
CloseLibrary(PopupMenuBase);
}
+ if (ami_open_resources() == false) { /* alloc message ports */
+ ami_misc_fatal_error("Unable to allocate resources");
+ return RETURN_FAIL;
+ }
+
+ if(ami_scheduler_process_create(schedulermsgport) != NSERROR_OK) {
+ ami_misc_fatal_error("Failed to initialise scheduler");
+ return RETURN_FAIL;
+ }
+
user = GetVar("user", temp, 1024, GVF_GLOBAL_ONLY);
current_user = ASPrintf("%s", (user == -1) ? "Default" : temp);
current_user_dir = ASPrintf("PROGDIR:Users/%s", current_user);
@@ -5365,11 +5374,6 @@ int main(int argc, char** argv)
ami_mime_init("PROGDIR:Resources/mimetypes");
sprintf(temp, "%s/mimetypes.user", current_user_dir);
ami_mime_init(temp);
- if(ami_schedule_create() == false) {
- ami_misc_fatal_error("Failed to initialise scheduler");
- return RETURN_FAIL;
- }
-
amiga_plugin_hack_init();
ret = amiga_datatypes_init();
@@ -5396,11 +5400,6 @@ int main(int argc, char** argv)
if(current_user_cache != NULL) FreeVec(current_user_cache);
ret = amiga_icon_init();
- if (ami_open_resources() == false) { /* alloc ports/asl reqs, open libraries/devices */
- ami_misc_fatal_error("Unable to allocate resources");
- return RETURN_FAIL;
- }
-
search_web_init(nsoption_charp(search_engines_file));
ami_clipboard_init();
ami_openurl_open();
@@ -5410,6 +5409,7 @@ int main(int argc, char** argv)
save_complete_init();
ami_theme_init();
ami_init_mouse_pointers();
+ ami_file_req_init();
win_destroyed = false;
ami_font_setdevicedpi(0); /* for early font requests, eg treeview init */
diff --git a/amiga/schedule.c b/amiga/schedule.c
index 6f2037d7e..607c3d8e5 100755
--- a/amiga/schedule.c
+++ b/amiga/schedule.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, 2011 Chris Young <chris@unsatisfactorysoftware.co.uk>
+ * Copyright 2008 - 2014 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -18,6 +18,7 @@
#include "amiga/os3support.h"
+#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/timer.h>
@@ -26,9 +27,15 @@
#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;
+
struct nscallback
{
struct TimeVal tv;
@@ -37,6 +44,21 @@ struct nscallback
struct TimeRequest *treq;
};
+struct ami_schedule_message {
+ struct Message msg;
+ int type;
+ int t;
+ void *callback;
+ void *p;
+};
+
+enum {
+ AMI_S_SCHEDULE = 0,
+ AMI_S_RUN,
+ AMI_S_STARTUP,
+ AMI_S_EXIT
+};
+
static PblHeap *schedule_list;
/**
@@ -201,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;
@@ -216,12 +260,20 @@ 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 void ami_schedule_open_timer(void)
+
+static struct MsgPort *ami_schedule_open_timer(void)
{
- msgport = AllocSysObjectTags(ASOT_PORT,
+ struct MsgPort *msgport = AllocSysObjectTags(ASOT_PORT,
ASO_NoTrack,FALSE,
TAG_DONE);
@@ -235,61 +287,239 @@ static void ami_schedule_open_timer(void)
TimerBase = (struct Device *)tioreq->Request.io_Device;
ITimer = (struct TimerIFace *)GetInterface((struct Library *)TimerBase,"main",1,NULL);
+
+ return msgport;
}
-static void ami_schedule_close_timer(void)
+static void ami_schedule_close_timer(struct MsgPort *msgport)
{
if(ITimer) DropInterface((struct Interface *)ITimer);
CloseDevice((struct IORequest *) tioreq);
- FreeSysObject(ASOT_IOREQUEST,tioreq);
- FreeSysObject(ASOT_PORT,msgport);
+ FreeSysObject(ASOT_IOREQUEST, tioreq);
+ FreeSysObject(ASOT_PORT, msgport);
}
-/* exported function documented in amiga/schedule.h */
-bool ami_schedule_create(void)
+/**
+ * Initialise amiga scheduler
+ *
+ * /return true if initialised ok or false on error.
+ */
+static struct MsgPort *ami_schedule_create(void)
{
- ami_schedule_open_timer();
+ struct MsgPort *msgport = ami_schedule_open_timer();
schedule_list = pblHeapNew();
- if(schedule_list == PBL_ERROR_OUT_OF_MEMORY) return false;
+ if(schedule_list == PBL_ERROR_OUT_OF_MEMORY) return NULL;
pblHeapSetCompareFunction(schedule_list, ami_schedule_compare);
- return true;
+ return msgport;
}
-/* exported function documented in amiga/schedule.h */
-void ami_schedule_free(void)
+/**
+ * Finalise amiga scheduler
+ *
+ */
+static void ami_schedule_free(struct MsgPort *msgport)
{
schedule_remove_all();
pblHeapFree(schedule_list); // this should be empty at this point
schedule_list = NULL;
- ami_schedule_close_timer();
+ ami_schedule_close_timer(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 = AllocSysObjectTags(ASOT_PORT, TAG_END);
+ struct MsgPort *timermsgport = ami_schedule_create();
+ bool running = true;
+ struct TimerRequest *timermsg = NULL;
+ ULONG schedulesig = 1L << schedulermsgport->mp_SigBit;
+ ULONG timersig = 1L << timermsgport->mp_SigBit;
+ uint32 signalmask = schedulesig | timersig;
+ uint32 signal = 0;
+
+ /* 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 = AllocSysObjectTags(ASOT_MESSAGE,
+ ASOMSG_Size, sizeof(struct ami_schedule_message),
+ ASOMSG_ReplyPort, schedulermsgport,
+ TAG_END);
+
+ asmsg->type = AMI_S_STARTUP;
+ PutMsg(nsmsgport, (struct Message *)asmsg);
+
+ /* Main loop for this process */
+
+ while(running) {
+ signal = Wait(signalmask);
+
+ if(signal & timersig) {
+ while((timermsg = (struct TimerRequest *)GetMsg(timermsgport))) {
+ ami_scheduler_run(nsmsgport);
+ //ReplyMsg((struct Message *)timermsg); /* \todo why does this crash? */
+ }
+ }
+
+ if(signal & schedulesig) {
+ while((asmsg = (struct ami_schedule_message *)GetMsg(schedulermsgport))) {
+ 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 */
+ }
+ }
+ }
+ }
+
+ ami_schedule_free(timermsgport);
+
+ return RETURN_OK;
+}
+
+
+/**
+ * Create a new process for the scheduler.
+ *
+ * \param nsmsgport Message port to send scheduler events to.
+ * \return NSERROR_OK on success or error code on faliure.
+ */
+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_scheduler_process,
+ NP_Child, TRUE,
+ NP_StackSize, 16384,
+ NP_Priority, 1,
+ NP_UserData, nsmsgport,
+ TAG_DONE);
+
+ if(proc == NULL) {
+ 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;
+}
+
diff --git a/amiga/schedule.h b/amiga/schedule.h
index 9fcec9a82..cfea4d917 100755
--- a/amiga/schedule.h
+++ b/amiga/schedule.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 Chris Young <chris@unsatisfactorysoftware.co.uk>
+ * Copyright 2008-2014 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -18,15 +18,8 @@
#ifndef AMIGA_SCHEDULE_H
#define AMIGA_SCHEDULE_H
-#include <proto/timer.h>
#include "amiga/os3support.h"
-struct Device *TimerBase;
-struct TimerIFace *ITimer;
-
-struct TimeRequest *tioreq;
-struct MsgPort *msgport;
-
/**
* Schedule a callback.
*
@@ -41,26 +34,23 @@ struct MsgPort *msgport;
nserror ami_schedule(int t, void (*callback)(void *p), void *p);
/**
- * Initialise amiga scheduler
+ * Handle a message received from the scheduler process.
*
- * /return true if initialised ok or false on error.
+ * \param nsmsgport Message port to process.
*/
-bool ami_schedule_create(void);
+void ami_schedule_handle(struct MsgPort *nsmsgport);
/**
- * Finalise amiga scheduler
+ * Create a new process for the scheduler.
*
+ * \param nsmsgport Message port for the scheduler to send events to.
+ * \return NSERROR_OK on success or error code on failure.
*/
-void ami_schedule_free(void);
+nserror ami_scheduler_process_create(struct MsgPort *nsmsgport);
/**
- * 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.
+ * Signal the scheduler process to exit.
*/
-void schedule_run(void);
-
+void ami_scheduler_process_delete(void);
#endif