home *** CD-ROM | disk | FTP | other *** search
- class SynchroObject;
- class Process;
- class Thread;
- class ThreadQ;
- class Scheduler;
- class Callstate;
-
- extern Thread *systhread;
-
- extern private_t Thread *thisthread; // always refers to running thread
- extern Process* thisproc;
-
- #define TF_SCHEDULER 0x01 /* special thread. Loops only */
- #define TF_KEEPSTACK 0x02 /* dont init stack on runrun */
- #define TF_INCOMPLETE 0x04 /* must acquire a stack before run */
- #define TF_NONPREEMPTABLE 0x08 /* can not preempt */
- #define TF_WILLJOIN 0x20 /* someone will join on it */
-
-
- #define TS_IDLE 0x01 /* useful, but not started */
- #define TS_RUNNING 0x02 /* busy */
- #define TS_READY 0x04 /* living in the readyq */
-
- #define TS_BLOCKED 0x20 /* blocked. Don't care on what */
-
- #define TS_LOCKED 0x80 /* unused */
- #define TS_STOPPED 0x100 /* thread is unconditionally stopped */
-
- #define TS_VIRGIN 0x400 /* thread not yet begun */
- #define TS_ERROR 0x800 /* something amiss */
- #define TS_DELETE 0x1000 /* no more trips to bed */
- //
- // FINISHED should be part of the flags and not the state.
- //
- #define TS_FINISHED 0x2000 /* all done */
- #define TS_ANY (~0) /* matches all */
- #define TP_BASEPRIO 0 /* base priority */
-
-
-
- //
- // WARNING: A CHANGE TO THIS CLASS OR ANY OF ITS BASE CLASSES MAY REQUIRE
- // RECOMPUTING THE STRUCT OFFSETS USED IN swtch!!
- //
-
- class Stack;
- class Thread : public Object {
- protected:
- // *** The offsets of t_csp, t_fp and t_proc are known to swtch().
- int *t_csp; // current stack pointer
- int *t_fp; // frame pointer
- Process *t_proc; // who is running me now
- union {
- Stack *stack;
- int neededstacksize;
- } ut_stack;
- #define t_stack ut_stack.stack
- #define t_neededstacksize ut_stack.neededstacksize
- int t_state; // current state
- int t_flags; // internal only flags
- #ifdef sun
- int t_pc;
- #endif sun
- #ifdef vax
- int t_pc; // needed for Ultrix preemption
- #endif vax
- int t_tag; // given tag on birth (UNIQUE)
- int t_tid; // user's tag name
- int t_pri; // thread priority
- int t_expired; // true iff timeslice expired
- int t_slockcount; // number of spinlocks held/spinning
- Objany t_data; // for getdata/setdata
- Objany t_boundobj; // what we are bound to
- Callstate t_callstate; // initial call state
- SynchroObject *t_blockedon; // Synchro object we are blked on
- // redo
- union {
- Thread* thread; // thread waiting
- Objany value; // ready value
- } ut_join;
- #define t_jthread ut_join.thread
- #define t_jvalue ut_join.value
- virtual void t_start1(Objany obj); // second half of fork/start
- public:
- Thread(char* name=0, int tid = 0,
- long ssiz = DEFSTACKSIZ, int musthavestack = 0);
- Thread(int tid);
- virtual Thread* newthread(char* name=0, int tid = 0, // vtl ctr
- long ssiz = DEFSTACKSIZ, int musthavestack = 0);
- virtual ~Thread(); // nuke a thread
- virtual int start(Objany obj, PFany pf, ...); // enqueue
- #define NOJOIN 0
- #define WILLJOIN TF_WILLJOIN
- // Usage: thisthread->fork({NO,WILL}JOIN, ...)
- virtual Thread* fork(int needjoin, Objany obj, PFany pf, ...);
- virtual int runrun(); // LIFE STARTS HERE
- virtual int run();
- void swtch(); // back to the sched thread
- virtual void sleep(SynchroObject* so = 0); // relinquish
- virtual void wakeup(SynchroObject* so = 0); // resume
- virtual void willjoin(); // want to join
- virtual Objany join(); // please join
- virtual void terminate(Objany retobj=0); // thread is finished
- // virtual void setaffinity(Process* p); // mark affinity
- void setdata(Objany data)
- { t_data = data; }
- Objany getdata()
- { return t_data; }
- void setstate(int newstate)
- { t_state = newstate; }
- void orstate(int st)
- // { ATOMIC_ORL(&t_state, st); }
- { t_state |= st; }
- void andstate(int st)
- // { ATOMIC_ANDL(&t_state, st); }
- { t_state &= st; }
- void isready()
- { orstate(TS_READY); }
- void setflags(int newflags)
- { t_flags = newflags; }
- void holdingspinlock()
- { t_slockcount++; }
- void releasingspinlock()
- { t_slockcount--; }
- int inspinlock()
- { return(t_slockcount); }
- inline Stack *stack();
- int *csp()
- { return t_csp; }
- int flags()
- { return t_flags; }
- #ifdef sun
- void setpc(int pc)
- {t_pc = pc;}
- int getpc()
- {return t_pc;}
- #endif sun
- #ifdef vax
- void setpc(int pc)
- {t_pc = pc;}
- int getpc()
- {return t_pc;}
- #endif vax
- int state()
- { return t_state; }
- int tag()
- { return t_tag; }
- int tid()
- { return t_tid; }
- void setpri(int newpri) // beware of multiple writers
- { t_pri= newpri; }
- int getpri()
- { return t_pri; }
- void setproc(Process* p)
- { t_proc = p; }
- Process *getproc()
- { return t_proc; }
- Process **proc()
- { return &t_proc; }
- inline void isrunning(); // mark thread running
- void isrunning2(); // but wait until it is done running
- inline void isnotrunning(); // as set by someone else
- int stackcnt()
- { return stack()->numstacksbuilt(); }
- int tagcnt();
- //
- // Preemption related cruft
- //
- void preemptable()
- { t_flags &= ~TF_NONPREEMPTABLE; }
- void nonpreemptable()
- { t_flags |= TF_NONPREEMPTABLE; }
- int ispreemptable()
- { return ( (t_flags & TF_NONPREEMPTABLE) == 0 ); }
- double cputime(); // in seconds
- int canpreempt();
- virtual void print(ostream& = cout);
- friend class ThreadQ;
- friend class ThreadQUnlocked;
- };
-
- //
- // Mark a thread as running. This should be called before
- // runrun. If the thread is already running, the caller will
- // wait. This guarantess that we don't have two scheduling threads
- // trouncing on this poor thread's stack. One guy coming down
- // into runrun, while the other guy is trying to return from it.
- // We don't have to lock anything, since there is only one ordering of
- // ops on the state that can cause problems,
- // and the problems are solved by delaying the
- // second thread here.
- //
-
-
- inline void
- Thread::isrunning()
- {
-
- if (t_state&TS_RUNNING)
- (void)isrunning2(); // looping wait
- orstate(TS_RUNNING);
- }
-
-
- //
- // This should be called after runrun
- //
- inline void
- Thread::isnotrunning()
- {
- // if not finished, and not running, balk
- if ( ((t_state&TS_FINISHED) == 0) && ((t_state&TS_RUNNING)== 0) )
- error("Thread is already not running\n");
- else
- andstate(~TS_RUNNING);
- }
-
- inline
- Stack*
- Thread::stack()
- {
- if (t_flags&TF_INCOMPLETE)
- error("Thread has no stack");
- return t_stack;
- }
-
-