home *** CD-ROM | disk | FTP | other *** search
- //
- //
- // Processes work as hungry puppies, banging on the scheduler
- // until a ready job is available or until someone bangs on the
- // process asking it to do something "out of band" (like pausing
- // or dying).
- //
- // Modification History:
- //
- // 05-Dec-89 John Faust
- // Remove stack free list. Allocate stacks of fixed size when thread
- // is allocated. Stack remains associated with owning thread. More
- // efficient (removes search of stack freelist for stack of proper size,
- // allocation of stack if one of proper size not found, and eliminates
- // need to balance local stack freelists).
- //
- // 08-Nov-1989 John Faust
- // Implement per-processor free lists of thread templates.
- //
-
- extern Process *sysproc;
-
- class Invocation;
-
- //
- // Maximum size of global thread freelist, threshhold of local list,
- // and number of threads to preallocate for local freelists.
- // Note that currently, thread size is 132 bytes.
- //
- // Using these values, the Create1M benchmark never has to allocate any threads
- // once the processes have been initialized.
- //
- #define GBL_THREAD_FREELIST_MAX 128
- #define LCL_THREAD_FREELIST_THRESH 8
- #define NUM_PREALLOC_THREADS 4
-
-
- class Process : public Object {
- #if (sun && THREAD_HAS_INTERRUPTIBLE_FIELD)
- int p_interruptible;
- #endif
- #ifdef vax
- // WARNING: The offset of p_interruptible is known to swtch().
- int p_interruptible;
- #endif vax
- char *p_name; // my name
- int p_id; // my id
- // WARNING: The offset of p_pid is known in hc_slock_asm.h
- int p_pid; // system pid
- int p_ppid; // system ppid
- //
- // Get and free threads from global shared thread freelist.
- // Processes go to the list only when their local freelist becomes
- // empty or when it gets to full.
- //
- void get_gbl_threads ();
- void free_gbl_threads ();
-
- protected:
- int p_state; // whats up
- int p_flags; // long term process stuff
- int p_request; // stop spinning on this
- Thread *p_schedthread; // where to swtch back to
- Thread *p_thread; // currently running thread
- ThreadQUnlocked* p_thread_freelist; // per-processor thd freelist
- #define NEWPROCESS
- virtual void p_fork(); // take care of the fork
- virtual void p_wait(); // where we spin
- virtual void p_pause(); // internal ::pause
- virtual void p_runchild(int *spinflag); // copy stack and go
- public:
- Process(int ptag, int id);
- Process();
- Process(char* name, int id, int delayedfork = 0); // fork in ctor
- virtual ~Process();
- // virtual newprocess function. After creation of the first thisproc,
- // raw process constructor is not used. thisproc->newprocess() is
- // used instead. User can assign his own derivation of Process to
- // thisproc in Main::init().
- virtual Process* newprocess(char* name,int id);
- virtual int request(int req);
- virtual void park(); // os pause
- virtual void drive(); // resume
- virtual int invoke();
-
- //
- // Get and free threads from per-processor freelist.
- //
- inline Thread* get_thread (int* init_reqd);
- inline void free_thread (Thread* t);
-
- int state()
- { return p_state; }
- void setstate(int st)
- { p_state = st; }
- int flags()
- { return p_flags; }
- inline int isroot();
- int id() // scheduler id
- {return p_id; }
- int pid() // unix id
- { return p_pid; }
- int ppid() // unix parent id
- { return p_ppid; }
- char * name()
- { return p_name; }
- Thread *schedthread()
- { return p_schedthread; }
- Thread *runningthread()
- { return p_thread; }
- #if (sun && THREAD_HAS_INTERRUPTIBLE_FIELD)
- int interruptible()
- { return p_interruptible; }
- inline int disable_interrupts();
- void enable_interrupts()
- { p_interruptible = 1; }
- #endif sun
- #ifdef vax
- int interruptible()
- { return p_interruptible; }
- inline int disable_interrupts();
- void enable_interrupts()
- { p_interruptible = 1; }
- #endif vax
- virtual void print(ostream& = cout);
- virtual void error(char *s);
- };
-
-
- #define R_NULL 0x00 /* nothing is happening */
- #define R_WAKEUP 0x01 /* wakeup wherever you are */
- #define R_PARK 0x02 /* put yourself to sleep in the OS */
- #define R_DIE 0x04 /* the nice way to kill a process */
- #define R_RETURN 0x08 /* relinquish control */
- /*
- * We don't need R_DIE and R_RETURN since the process wait routine
- * only understands how to R_RETURN from its scheduling loop. Where
- * it returns to is completely determined by how it was invoked.
- * If it was invoked from runchild, then we will return to there
- * and get nuked with a (delete this). If we were called via runrun
- * from the Main constructor, then we will return to single threaded
- * control.
- */
-
- #define S_RUN 0x01 /* running */
- #define S_WAIT 0x02 /* unused. waiting to be used in spinloop */
- #define S_SLEEP 0x04 /* sleeping on an event */
- #define S_OSPAUSE 0x08 /* WAITing or SLEEPing via OS pause */
- #define S_FREE (S_WAIT|S_OSPAUSE)
- #define S_ZOMBIE 0x10
- #define S_EXITING 0x20
- #define S_DELAYEDFORK 0x40 /* constructed, but not yet forked */
- #define S_FORKING 0x80 /* as we speak... */
- #define S_ERROR 0x100
- #define S_REAPED 0x200 /* already cleaned up */
- #define S_REAPING 0x400 /* parent process cleaning up */
-
-
- //
- // special proc tags for flags field
- //
- #define P_ROOT 0x01
-
- inline int Process::isroot()
- {
- return (p_flags&P_ROOT);
- }
-
- //
- // Get a thread from the process freelist. This is an unshared, unprotected
- // queue, so access to it should be very fast.
- //
- inline Thread*
- Process::get_thread (int* init_reqd)
- {
- register Thread* t;
-
- //
- // If this process' local freelist is exhausted, then try to grab some
- // more threads from the global queue.
- //
- if (p_thread_freelist->length() == 0)
- get_gbl_threads ();
-
- //
- // Check local freelist for reuseable thread. If none, allocate
- // a new one.
- //
- t = p_thread_freelist->get ();
- if (t)
- {
- *init_reqd = 0;
- // cout << "got thread from freelist\n";
- return t;
- }
- else
- {
- *init_reqd = 1;
- // cout << "had to alloc thread\n";
- return (t = (Thread*) new char [sizeof (Thread)]);
- }
- }
-
-
- //
- // Return a thread to the local freelist for this process.
- //
- inline void
- Process::free_thread (Thread* t)
- {
- p_thread_freelist->append (t);
-
- //
- // If the local freelist is over threshhold, move half it's threads
- // to the global freelist.
- //
- if (p_thread_freelist->length() > LCL_THREAD_FREELIST_THRESH)
- {
- free_gbl_threads ();
- }
- }
-
-
- #if (sun && THREAD_HAS_INTERRUPTIBLE_FIELD)
- inline int Process::disable_interrupts()
- {
- if (p_interruptible) {
- p_interruptible = 0;
- return 1;
-
- } else
- return 0;
- }
- #endif sun
- #ifdef vax
- inline int Process::disable_interrupts()
- {
- if (p_interruptible) {
- p_interruptible = 0;
- return 1;
-
- } else
- return 0;
- }
- #endif vax
-
- extern private_t Process *thisproc; // private to each proc
-