210 lines
5.1 KiB
C
210 lines
5.1 KiB
C
/*
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
* in the LICENSE file.
|
|
*/
|
|
|
|
/*
|
|
* Some notes on locking:
|
|
*
|
|
* All the locking woes come from implementing
|
|
* threadinterrupt (and threadkill).
|
|
*
|
|
* _threadgetproc()->thread is always a live pointer.
|
|
* p->threads, p->ready, and _threadrgrp also contain
|
|
* live thread pointers. These may only be consulted
|
|
* while holding p->lock or _threadrgrp.lock; in procs
|
|
* other than p, the pointers are only guaranteed to be live
|
|
* while the lock is still being held.
|
|
*
|
|
* Thread structures can only be freed by the proc
|
|
* they belong to. Threads marked with t->inrendez
|
|
* need to be extracted from the _threadrgrp before
|
|
* being freed.
|
|
*
|
|
* _threadrgrp.lock cannot be acquired while holding p->lock.
|
|
*/
|
|
|
|
typedef struct Pqueue Pqueue;
|
|
typedef struct Rgrp Rgrp;
|
|
typedef struct Tqueue Tqueue;
|
|
typedef struct Thread Thread;
|
|
typedef struct Execargs Execargs;
|
|
typedef struct Proc Proc;
|
|
|
|
/* must match list in sched.c */
|
|
typedef enum
|
|
{
|
|
Dead,
|
|
Running,
|
|
Ready,
|
|
Rendezvous,
|
|
} State;
|
|
|
|
typedef enum
|
|
{
|
|
Channone,
|
|
Chanalt,
|
|
Chansend,
|
|
Chanrecv,
|
|
} Chanstate;
|
|
|
|
enum
|
|
{
|
|
RENDHASH = 13,
|
|
Printsize = 2048,
|
|
NPRIV = 8,
|
|
};
|
|
|
|
struct Rgrp
|
|
{
|
|
Lock lock;
|
|
Thread *hash[RENDHASH];
|
|
};
|
|
|
|
struct Tqueue /* Thread queue */
|
|
{
|
|
int asleep;
|
|
Thread *head;
|
|
Thread **tail;
|
|
};
|
|
|
|
struct Thread
|
|
{
|
|
Lock lock; /* protects thread data structure */
|
|
jmp_buf sched; /* for context switches */
|
|
int id; /* thread id */
|
|
int grp; /* thread group */
|
|
int moribund; /* thread needs to die */
|
|
State state; /* run state */
|
|
State nextstate; /* next run state */
|
|
unsigned char *stk; /* top of stack (lowest address of stack) */
|
|
uint32_t stksize; /* stack size */
|
|
Thread *next; /* next on ready queue */
|
|
|
|
Proc *proc; /* proc of this thread */
|
|
Thread *nextt; /* next on list of threads in this proc*/
|
|
int ret; /* return value for Exec, Fork */
|
|
|
|
char *cmdname; /* ptr to name of thread */
|
|
|
|
int inrendez;
|
|
Thread *rendhash; /* Trgrp linked list */
|
|
void* rendtag; /* rendezvous tag */
|
|
void* rendval; /* rendezvous value */
|
|
int rendbreak; /* rendezvous has been taken */
|
|
|
|
Chanstate chan; /* which channel operation is current */
|
|
Alt *alt; /* pointer to current alt structure (debugging) */
|
|
|
|
void* udata[NPRIV]; /* User per-thread data pointer */
|
|
};
|
|
|
|
struct Execargs
|
|
{
|
|
char *prog;
|
|
char **args;
|
|
int fd[2];
|
|
};
|
|
|
|
struct Proc
|
|
{
|
|
Lock lock;
|
|
jmp_buf sched; /* for context switches */
|
|
int pid; /* process id */
|
|
int splhi; /* delay notes */
|
|
Thread *thread; /* running thread */
|
|
|
|
int needexec;
|
|
Execargs exec; /* exec argument */
|
|
Proc *newproc; /* fork argument */
|
|
char exitstr[ERRMAX]; /* exit status */
|
|
|
|
int rforkflag;
|
|
int nthreads;
|
|
Tqueue threads; /* All threads of this proc */
|
|
Tqueue ready; /* Runnable threads */
|
|
Lock readylock;
|
|
|
|
char printbuf[Printsize];
|
|
int blocked; /* In a rendezvous */
|
|
int pending; /* delayed note pending */
|
|
int nonotes; /* delay notes */
|
|
uint32_t nextID; /* ID of most recently created thread */
|
|
Proc *next; /* linked list of Procs */
|
|
|
|
void *arg; /* passed between shared and unshared stk */
|
|
char str[ERRMAX]; /* used by threadexits to avoid malloc */
|
|
|
|
void* wdata; /* Lib(worker) per-proc data pointer */
|
|
void* udata; /* User per-proc data pointer */
|
|
char threadint; /* tag for threadexitsall() */
|
|
};
|
|
|
|
struct Pqueue { /* Proc queue */
|
|
Lock lock;
|
|
Proc *head;
|
|
Proc **tail;
|
|
};
|
|
|
|
struct Ioproc
|
|
{
|
|
int tid;
|
|
Channel *c, *creply;
|
|
int inuse;
|
|
int32_t (*op)(va_list*);
|
|
va_list arg;
|
|
long ret;
|
|
char err[ERRMAX];
|
|
Ioproc *next;
|
|
};
|
|
|
|
void _freeproc(Proc*);
|
|
void _freethread(Thread*);
|
|
Proc* _newproc(void(*)(void*), void*, uint32_t, char*, int, int);
|
|
int _procsplhi(void);
|
|
void _procsplx(int);
|
|
void _sched(void);
|
|
int _schedexec(Execargs*);
|
|
void _schedexecwait(void);
|
|
void _schedexit(Proc*);
|
|
int _schedfork(Proc*);
|
|
void _schedinit(void*);
|
|
void _systhreadinit(void);
|
|
void _threadassert(char*);
|
|
void _threadbreakrendez(void);
|
|
void _threaddebug(uint32_t, char*, ...);
|
|
void _threadexitsall(char*);
|
|
void _threadflagrendez(Thread*);
|
|
Proc* _threadgetproc(void);
|
|
void _threadsetproc(Proc*);
|
|
void _threadinitstack(Thread*, void(*)(void*), void*);
|
|
void* _threadmalloc(int32_t, int);
|
|
void _threadnote(void*, char*);
|
|
void _threadready(Thread*);
|
|
void* _threadrendezvous(void*, void*);
|
|
void _threadsignal(void);
|
|
void _threadsysfatal(char*, ...);
|
|
void** _workerdata(void);
|
|
void _xinc(int32_t*);
|
|
long _xdec(int32_t*);
|
|
|
|
extern int _threaddebuglevel;
|
|
extern char* _threadexitsallstatus;
|
|
extern Pqueue _threadpq;
|
|
extern Channel* _threadwaitchan;
|
|
extern Rgrp _threadrgrp;
|
|
|
|
#define DBGAPPL (1 << 0)
|
|
#define DBGSCHED (1 << 16)
|
|
#define DBGCHAN (1 << 17)
|
|
#define DBGREND (1 << 18)
|
|
/* #define DBGKILL (1 << 19) */
|
|
#define DBGNOTE (1 << 20)
|
|
#define DBGEXEC (1 << 21)
|
|
|
|
#define ioproc_arg(io, type) (va_arg((io)->arg, type))
|