Article View: comp.sys.sequent
Article #234A new approach to Unix Threads
From: Gordon Russell
Date: Fri, 04 Sep 1992 09:28
Date: Fri, 04 Sep 1992 09:28
182 lines
6282 bytes
6282 bytes
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. |
+--------------------------------+-------------------------------------------+
Technical Details
Message-ID:
<10411@baird.cs.strath.ac.uk>Path:
arc1-ca.pugleaf.net!sparky!uunet!mcsun!uknet!strath-cs!gor@cs.strath.ac.ukShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!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