home *** CD-ROM | disk | FTP | other *** search
- /*
- * presto.c
- *
- * Main PRESTO bootstrapping code. Works something like this:
- *
- * main()
- * Create a new MAIN object.
- * delete the scheduler thread
- * exit
- *
- * Main::Main()
- * Call Main::init giving programmer chance to set up
- * initial parameters.
- *
- * - Bind "thisthread" to the default thread we get from UNIX.
- * - Create a new scheduler object.
- * - Create a thread to run in the scheduler object.
- * - Start new thread in scheduler object. We are running
- * without preemption and with a single processor at this
- * point, so the start just puts the thread/scheduler pair
- * on the ready queue.
- * - Create nummainthreads bound to Main::main and "start" them
- * by placing them on the run queue. Again, we know that
- * they won't run until the scheduler actually kicks in.
- *
- * - Invoke "thisproc" getting it to start pulling threads
- * off the readyq.
- */
-
- #define _PRESTO_C
-
-
- #include <sys/types.h>
- #include <osfcn.h>
- #include <stream.h>
- #include "presto.h"
-
- Scheduler *sched; // does not need to be shared,
- // just what it references does
-
- static int main_exit_code = 0; // how we leave
- shared_t int prestoState = STATIC_CTOR;
-
- Main::Main(int ac, char **ap, char **ep)
- {
- int strlen(char*);
- int strcpy(char*, char*);
- Thread *t, *mainthread;
-
- argc = ac;
- argv = ap;
- envp = ep;
- numprocessors = 1;
- mainstacksizes = DEFSTACKSIZ;
- nummainthreads = 1;
- quantum = DEFQUANTUM;
-
- mainthread = new Thread("_MAIN_", 0, 0); // run on same stack
- mainthread->setflags(TF_SCHEDULER|TF_KEEPSTACK|TF_NONPREEMPTABLE);
-
- //
- // "thisthread" refers to the current thread of execution running
- // right here, right now. Make our thread point at the static process
- // object until we have our own process object to reference into.
- //
- mainthread->setproc(sysproc);
- thisthread = mainthread;
-
- prestoState = MAIN_INIT;
- // give the programmer a chance
- if (main_exit_code = Main::init()) { // non-zero return
- return; // is bad news
- }
-
- #ifdef sun
- numprocessors = 1;
- #endif sun
- #ifdef vax
- // VAX unix version runs on uniprocessors only for now.
- numprocessors = 1;
- #endif vax
-
- if (thisthread != mainthread)
- thisthread = mainthread;
- prestoState = MAIN_MAIN;
-
- //
- // prime the scheduler
- //
- if (sched == (Scheduler*)0)
- sched = new Scheduler(numprocessors,quantum); // sets thisproc
-
- //
- // t becomes the first schedulable thread
- // Since we only have one processor, and no preemption here
- // we return with t on the ready q.
- //
- t = mainthread->newthread("SCHEDULER_STARTER");
- t->nonpreemptable();
-
- t->start(sched, (PFany)(sched->invoke));
-
- //
- // Build the main threads and readyq them
- //
- for (int i = 0; i < nummainthreads; i++) {
- char buf[8]; // lotsa threads
- sprintf(buf,"%s.%d", MAINNAME, i);
- char *name = new char[strlen(buf)+1];
- strcpy(name, buf);
- Thread *t = mainthread->newthread(name, i+1, mainstacksizes);
- t->start(this, (PFany)(this->main));
- }
-
- // Crank up the scheduler in the context of thisthread.
- // This will read the SCHEDULER thread off the
- // the readyq, invoke that thread
- // on the scheduler itself, which will cause the scheduler
- // to then create numprocessors copies of itself (each
- // running on its own stack). The SCHEDULER thread
- // is guaranteed not to block and will be the first thread
- // to terminate, so we can quickly reuse it.
- //
-
- //
- // Bind this thread to a processor which will start up all the
- // coschedulers. Thisthread will not be queued since it's a scheduler.
- // We have to start it up directly.
- //
-
- mainthread->isrunning();
- thisproc->invoke(); // start thisproc which will start
- // the scheduler thread which will
- // start all the processor threads
- // which will then pull the main
- // threads off the readyq
- mainthread->isnotrunning();
-
- //
- // Since shutdown is not synchronized, there is a race condition which
- // can result in sched getting deleted while process objects are still
- // active. If it hurts, don't do it.
- //
- // if (sched)
- // delete sched;
- //
-
- delete thisproc;
- thisproc = sysproc;
-
- //delete thisthread; /* done in runrun */
- //thisthread = 0;
- //
- // Threads are out... thisthread is undefined at this point
- //
- cout << "HALT\n"; // should be single unix process
- prestoState = MAIN_DONE;
- main_exit_code = Main::done();
- }
-
-
- Main::~Main()
- {
- }
-
-
- //
- // Preallocate tons of threads in the parent process's address space.
- // This is a temporary hack to get around the brain-damaged sequent
- // shared memory implementation.
- //
- // NOTE: not called from anywhere in Presto.
- //
- int
- Main::preallocthreads(int cnt, int sz)
- {
- int j;
-
- j = cnt;
- Thread **tlist = new Thread*[j];
- while (j--) {
- tlist[j] = thisthread->newthread("any",
- 0, // any id
- sz, // stack size
- 1); // must have stack
- }
- j = cnt;
- while (j--) {
- delete tlist[j];
- }
- delete tlist;
- return cnt;
- }
-
- typedef void (*PF)();
- extern PF set_new_handler(PF);
- extern void failed_malloc();
-
- void
- main(int argc, char **argv, char **envp)
- {
- set_new_handler(failed_malloc);
-
- //
- // Create a new main thread
- //
- Main *MAIN = new Main(argc, argv, envp);
-
- if (MAIN)
- delete MAIN;
-
- prestoState = STATIC_DTOR;
-
- extern wait(int*);
- while (::wait(0) != -1) // collect kids, get execution stats
- continue;
-
- exit(main_exit_code);
- }
-