home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!mcsun!uknet!strath-cs!gor@cs.strath.ac.uk
- From: gor@cs.strath.ac.uk (Gordon Russell)
- Newsgroups: comp.sys.sequent
- Subject: A new approach to Unix Threads
- Message-ID: <10411@baird.cs.strath.ac.uk>
- Date: 4 Sep 92 09:28:56 GMT
- Sender: gor@cs.strath.ac.uk
- Organization: Comp. Sci. Dept., Strathclyde Univ., Glasgow, Scotland.
- Lines: 182
-
-
- I have been working on a simple threads package which preferably
- would work on the two classes of machines I currently have access to..
- sun4s and a sequent symmetry. I have been trying to achieve this
- through the use of a context switch during signal handling (triggered
- under a setitimer event). However, this does not appear to work
- well on the symmetry (but only slightly better on the Sun4s :-) ).
- Could someone out there help me by having a quick look at my code?
- Sorry to waste general news bandwidth with a program (it is pretty small
- though). Even some suggestions would be useful, for I am at the end of my
- teather.
-
- This program is not the best one I have to do this. The best that I have
- achieved so far is one which doesn't core dump, but will corrupt the
- totals being calculated in the two tasks of the context switch occurred
- during a calculation loop. I have a feeling that the signal handler just
- does not allow me the access to system registers that I require.
- Again, please dont flame me for posting a program..., but feel free
- to email me or post with any (helpfull) comments.
-
- PS I know about the threads package which comes in xtank, but it is a
- volenterary (sp?) thread switch, which is unsuitable for my application.
-
-
- /* Compile with -DSYMMETRY */
-
- #include <stdio.h>
- #include <signal.h>
- #include <sys/time.h>
-
- #define TASK_OFF (1<<(SIGVTALRM-1))
- #define TASK_ON (0)
- #define INTERVAL (500000)
-
- #define DISABLE_TASK_SWITCH() sigsetmask(TASK_OFF)
- #define ENABLE_TASK_SWITCH() sigsetmask(TASK_ON)
-
- typedef struct {
- int number_of_tasks;
- struct sigcontext *context;
- int last_task;
- } task_structure;
-
- static task_structure TASKINFO;
-
- /*
- * Copy the current context to its save buffer in task_structure, and write in
- * the next context.
- */
- void swap_context(newcont,oldcont,context)
- int newcont,oldcont;
- struct sigcontext *context;
- {
- TASKINFO.context[oldcont] = *context;
- *context = TASKINFO.context[newcont];
- }
-
- /*
- * SIGNAL handler routine, which selects the next thread, swaps to that
- * context, and then returns, thus activating the new thread.
- */
- task_control(sig,code,context)
- int sig,code;
- struct sigcontext *context;
- {
- struct itimerval timer;
- int newcontext_no;
-
- /* Get the next thread's process id */
- newcontext_no = TASKINFO.last_task+1;
- if (newcontext_no > TASKINFO.number_of_tasks) newcontext_no = 0;
-
- /* Select the new thread */
- swap_context(newcontext_no,TASKINFO.last_task,context);
- TASKINFO.last_task = newcontext_no;
-
- /* Set the round-robin scheduler interrupt timer */
- timer.it_value.tv_sec = 0;
- timer.it_value.tv_usec = INTERVAL;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = 0;
- if (setitimer(ITIMER_VIRTUAL,&timer,NULL)) perror();
- }
-
- void startup_tasking()
- {
- struct itimerval timer;
- struct sigvec task_struct;
- struct sigstack sig;
-
- /* Initialise the save buffer with enough space to save the MAIN thread */
- TASKINFO.number_of_tasks = 0;
- TASKINFO.context = (struct sigcontext *)malloc(sizeof(struct sigcontext));
- TASKINFO.last_task = 0;
-
- /* Create a signal stack for the scheduler to run on */
- sig.ss_sp = (char *)malloc(1024);
- sig.ss_onstack = 0;
- if (sigstack (&sig,NULL) != 0) perror();
-
- /* Insert the scheduler into the signal handler table */
- task_struct.sv_handler = task_control;
- task_struct.sv_mask = TASK_OFF;
- #ifdef SYMMETRY
- task_struct.sv_onstack = 1;
- #endif
- if (sigvec(SIGVTALRM,&task_struct,NULL) != 0) perror;
-
- /* Start off the timer to activate scheduler */
- timer.it_value.tv_sec = 0;
- timer.it_value.tv_usec = INTERVAL;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = 0;
- if (setitimer(ITIMER_VIRTUAL,&timer,NULL)) perror();
- }
-
- /*
- * This identifies a function as a task.
- */
- void background_task(task_addr)
- void (* task_addr)();
- {
- char *newstack;
- struct sigcontext *cont;
- int bank,reg;
- DISABLE_TASK_SWITCH(); /* Dont allow the scheduler to run here */
- newstack = (char *)malloc(4000); /* Create a new stack for the process */
- TASKINFO.number_of_tasks+=1; /* Increment the no of threads in system */
- TASKINFO.context = (struct sigcontext *)
- realloc(TASKINFO.context,(TASKINFO.number_of_tasks+1) * sizeof(struct sigcontext));
-
- /* Set up the initial state of the new thread */
- #ifdef SYMMETRY
- cont = TASKINFO.context+TASKINFO.number_of_tasks;
- cont->sc_onstack = 0; /* sigstack state to restore */
- cont->sc_mask = TASK_ON ; /* signal mask to restore */
- cont->sc_sp = (int)newstack; /* sp to restore */
- cont->sc_pc = (int)task_addr; /* pc to restore */
- #endif
-
- ENABLE_TASK_SWITCH(); /* Restart the scheduler now */
- }
-
- void task2()
- {
- int a,b,c;
- c=0;
- do {
- DISABLE_TASK_SWITCH();
- b=0; for (a=1; a<90000; a++) b+=a;
- ENABLE_TASK_SWITCH();
- printf ("Completed 90000 sum %x\n",b);
- }while (1);
- }
-
- void task1()
- {
- int a,b,c;
- c=0;
- do {
- b=0; for (a=1; a<100000; a++) b+=a;
- printf ("Completed 100000 sum %x\n",b);
- }while (1);
- }
-
- main()
- {
- startup_tasking();
- ENABLE_TASK_SWITCH();
- background_task(task2);
- task1();
- }
-
-
- +--------------------------------+-------------------------------------------+
- | Gordon Russell | EMAIL : gor@cs.strath.ac.uk |
- | L13.13a, Livingstone Tower, | TELEPHONE : 041-552-4400 Ex 3703 |
- | University Of Strathclyde, | FAX : 041-552-0775 |
- | 26 Richmond Street, +-------------------------------------------+
- | Glasgow, G1 1XH | Spelling mistakes within this document are|
- | Scotland, UK | caused by internet compaction algorithms. |
- +--------------------------------+-------------------------------------------+
-