Annotation of coherent/b/STREAMS/coh.386/proc.c, revision 1.1

1.1     ! root        1: /* $Header: /src386/STREAMS/coh.386/RCS/proc.c,v 2.3 93/08/09 13:35:59 bin Exp Locker: bin $ */
        !             2: /* (lgl-
        !             3:  *     The information contained herein is a trade secret of Mark Williams
        !             4:  *     Company, and  is confidential information.  It is provided  under a
        !             5:  *     license agreement,  and may be  copied or disclosed  only under the
        !             6:  *     terms of  that agreement.  Any  reproduction or disclosure  of this
        !             7:  *     material without the express written authorization of Mark Williams
        !             8:  *     Company or persuant to the license agreement is unlawful.
        !             9:  *
        !            10:  *     COHERENT Version 3.x, 4.x
        !            11:  *     Copyright (c) 1982, 1993.
        !            12:  *     An unpublished work by Mark Williams Company, Chicago.
        !            13:  *     All rights reserved.
        !            14:  -lgl) */
        !            15: /*
        !            16:  * Process handling and scheduling.
        !            17:  *
        !            18:  * $Log:       proc.c,v $
        !            19:  * Revision 2.3  93/08/09  13:35:59  bin
        !            20:  * Kernel 82 changes
        !            21:  * 
        !            22:  * Revision 2.2  93/07/26  15:53:52  nigel
        !            23:  * Nigel's R80
        !            24:  * 
        !            25:  */
        !            26: 
        !            27: #include <common/_wait.h>
        !            28: #include <kernel/_sleep.h>
        !            29: #include <kernel/ker_data.h>
        !            30: #include <kernel/sigproc.h>
        !            31: #include <sys/wait.h>
        !            32: #include <stddef.h>
        !            33: 
        !            34: #include <sys/coherent.h>
        !            35: #include <sys/acct.h>
        !            36: #include <sys/errno.h>
        !            37: #include <sys/inode.h>
        !            38: #include <sys/ptrace.h>
        !            39: #include <sys/sched.h>
        !            40: #include <signal.h>
        !            41: #include <sys/stat.h>
        !            42: 
        !            43: /*
        !            44:  * Initialization.
        !            45:  * Set up the hash table queues.
        !            46:  */
        !            47: pcsinit()
        !            48: {
        !            49:        register PROC *pp;
        !            50:        register PLINK *lp;
        !            51: 
        !            52:        /*
        !            53:         * Explicitly initialize everything in the first process. We use the
        !            54:         * kernel initialize routine with SELF set to NULL so that the first
        !            55:         * process gets started out with default values for fields that are
        !            56:         * normally inherited.
        !            57:         */
        !            58: 
        !            59:        pp = & procq;
        !            60:        procq.p_nforw = pp;
        !            61:        procq.p_nback = pp;
        !            62:        procq.p_lforw = pp;
        !            63:        procq.p_lback = pp;
        !            64: 
        !            65:        /* Segments are initialized in mchinit() and eveinit(). */
        !            66:        /* procq is static, so p_shmsr[] initializes to nulls.  */
        !            67: 
        !            68:        PROC_INIT (& procq);
        !            69: 
        !            70:        for (lp = linkq ; lp < linkq + NHPLINK ; lp ++) {
        !            71:                lp->p_lforw = lp;
        !            72:                lp->p_lback = lp;
        !            73:        }
        !            74: 
        !            75:        /*
        !            76:         * After we have set things up, we can have a current process.
        !            77:         */
        !            78: 
        !            79:        SELF = pp;
        !            80: }
        !            81: 
        !            82: /*
        !            83:  * Initiate a process.
        !            84:  */
        !            85: 
        !            86: static PROC *
        !            87: process ()
        !            88: {
        !            89:        register PROC *pp1;
        !            90:        register PROC *pp;
        !            91: 
        !            92:        if ((pp = kalloc (sizeof (PROC))) == NULL)
        !            93:                return NULL;
        !            94: 
        !            95:        PROC_INIT (pp);
        !            96: 
        !            97:        lock (pnxgate);
        !            98: next:
        !            99: 
        !           100:        /*
        !           101:         * Pick the next process id.
        !           102:         */
        !           103:        if (++ cpid >= NPID)
        !           104:                cpid = 2;
        !           105:        pp->p_pid = cpid;
        !           106: 
        !           107: 
        !           108:        /*
        !           109:         * Make sure that process id is not in use.
        !           110:         */
        !           111: 
        !           112:        pp1 = & procq;
        !           113:        while ((pp1 = pp1->p_nforw) != & procq) {
        !           114:                if (pp1->p_pid < pp->p_pid)
        !           115:                        break;
        !           116:                if (pp1->p_pid == pp->p_pid)
        !           117:                        goto next;
        !           118:        }
        !           119: 
        !           120:        /*
        !           121:         * We've got a valid pid, so let's put this process into
        !           122:         * the process table.
        !           123:         */
        !           124: 
        !           125:        pp->p_nback = pp1->p_nback;
        !           126:        pp1->p_nback->p_nforw = pp;
        !           127:        pp->p_nforw = pp1;
        !           128:        pp1->p_nback = pp;
        !           129:        unlock (pnxgate);
        !           130:        return pp;
        !           131: }
        !           132: 
        !           133: /*
        !           134:  * Remove a process from the next queue and release and space.
        !           135:  */
        !           136: relproc(pp)
        !           137: register PROC *pp;
        !           138: {
        !           139:        register SEG * sp;
        !           140: 
        !           141:        /*
        !           142:         * Child process still has a user-area.
        !           143:         */
        !           144:        if (sp = pp->p_segp[SIUSERP]) {
        !           145: 
        !           146:                /*
        !           147:                 * Detach user-area from child process.
        !           148:                 */
        !           149:                pp->p_segp[SIUSERP] = NULL;
        !           150: 
        !           151:                /*
        !           152:                 * Child process is swapped out.
        !           153:                 */
        !           154:                if (pp->p_flags & PFSWAP)
        !           155:                        sp->s_lrefc++;
        !           156: 
        !           157:                /*
        !           158:                 * Release child's user-area.
        !           159:                 */
        !           160:                sfree(sp);
        !           161:        }
        !           162: 
        !           163:        /*
        !           164:         * Remove process from doubly-linked list of all processes.
        !           165:         * Release space allocated for proc structure.
        !           166:         */
        !           167:        lock(pnxgate);
        !           168:        pp->p_nback->p_nforw = pp->p_nforw;
        !           169:        pp->p_nforw->p_nback = pp->p_nback;
        !           170:        unlock(pnxgate);
        !           171:        kfree(pp);
        !           172: }
        !           173: 
        !           174: /*
        !           175:  * Create a clone of ourselves.
        !           176:  *     N.B. - consave(&mcon) returns twice; anything not initialized
        !           177:  *     in automatic storage before the call to segadup() will not be
        !           178:  *     initialized when the second return from consave() commences.
        !           179:  */
        !           180: pfork()
        !           181: {
        !           182:        register PROC *cpp;
        !           183:        register PROC *pp;
        !           184:        register int s;
        !           185:        MCON mcon;
        !           186: 
        !           187:        if ((cpp = process ()) == NULL) {
        !           188:                SET_U_ERROR( EAGAIN, "no more process table entries" );
        !           189:                return -1;
        !           190:        }
        !           191: 
        !           192:        s = sphi();     /* put current interrupt level into s before segadup */
        !           193:        spl(s);
        !           194: 
        !           195:        /*
        !           196:         * As stated above, no auto variable may be changed between calls
        !           197:         * to segadup() and consave().
        !           198:         */
        !           199: 
        !           200:        if (segadup(cpp) == 0) {
        !           201:                SET_U_ERROR( EAGAIN, "can not duplicate segments" );
        !           202:                relproc(cpp);
        !           203:                return -1;
        !           204:        }
        !           205: 
        !           206:        shmDup(cpp);    /* copy shared memory info & update ref counts */
        !           207: 
        !           208:        if (u.u_rdir)
        !           209:                u.u_rdir->i_refc ++;
        !           210:        if (u.u_cdir)
        !           211:                u.u_cdir->i_refc ++;
        !           212:        fdadupl ();
        !           213: 
        !           214:        sphi ();                /* s = sphi() was done before segadup() */
        !           215:        consave (& mcon);
        !           216:        spl (s);
        !           217: 
        !           218:        /*
        !           219:         * Parent process.
        !           220:         */
        !           221: 
        !           222:        if ((pp = SELF) != cpp) {
        !           223:                segfinm (cpp->p_segp [SIUSERP]);
        !           224:                dmaout (sizeof (mcon),
        !           225:                        MAPIO (cpp->p_segp [SIUSERP]->s_vmem,
        !           226:                               U_OFFSET + offsetof (struct uproc, u_syscon)),
        !           227:                        (char *) & mcon);
        !           228:                s = sphi ();
        !           229:                setrun (cpp);
        !           230:                spl (s);
        !           231: 
        !           232:                u.u_rval2 = 0;
        !           233:                return cpp->p_pid;
        !           234:        } else {
        !           235:                /*
        !           236:                 * Child process.
        !           237:                 */
        !           238: 
        !           239:                u.u_btime = timer.t_time;
        !           240:                u.u_flag = AFORK;
        !           241: 
        !           242: #ifdef UPROC_VERSION
        !           243:                u.u_version = UPROC_VERSION;
        !           244: #endif /* UPROC_VERSION */
        !           245:                u.u_sleep [0] = '\0'; /* We are not sleeping to start with.  */
        !           246:                sproto (0);
        !           247:                segload ();
        !           248:                u.u_rval2 = SELF->p_ppid;
        !           249:                return 0;
        !           250:        }
        !           251: }
        !           252: 
        !           253: /*
        !           254:  * Die.
        !           255:  */
        !           256: pexit(s)
        !           257: {
        !           258:        register PROC *pp1;
        !           259:        register PROC *pp;
        !           260:        register SEG  *sp;
        !           261:        register int n;
        !           262:        PROC          * parent = NULL;
        !           263: 
        !           264:        pp = SELF;
        !           265:        T_PIGGY( 0x1, printf("%s:pexit(%x)", u.u_comm, s));
        !           266: 
        !           267:        ndpEndProc ();
        !           268: 
        !           269:        /*
        !           270:         * Cancel alarm and poll timers [if any].
        !           271:         */
        !           272:        timeout(&pp->p_alrmtim, 0, NULL, 0);
        !           273:        timeout(&pp->p_polltim, 0, NULL, 0);
        !           274: 
        !           275:        /*
        !           276:         * Write out accounting directory and close all files associated with
        !           277:         * this process.
        !           278:         */
        !           279:        setacct();
        !           280:        if (u.u_rdir)
        !           281:                ldetach(u.u_rdir);
        !           282:        if (u.u_cdir)
        !           283:                ldetach(u.u_cdir);
        !           284:        fdaclose();
        !           285: 
        !           286:        /*
        !           287:         * Free all segments in reverse order, except for user-area.
        !           288:         */
        !           289:        for (n = NUSEG; --n > 0;) {
        !           290:                if (sp = pp->p_segp[n]) {
        !           291:                        pp->p_segp[n] = NULL;
        !           292:                        sfree(sp);
        !           293:                }
        !           294:        }
        !           295: 
        !           296:        /* Detach remaining shared memory segments. */
        !           297:        shmAllDt();
        !           298: 
        !           299:        /* Adjust(undo) all semaphores. */
        !           300:        semAllAdjust(pp);
        !           301: 
        !           302:        /*
        !           303:         * Wakeup our parent.  If we have any children, init will become the
        !           304:         * new parent.  If there are any children we are tracing who are
        !           305:         * waiting for us, we wake them up.
        !           306:         */
        !           307:        pp1 = &procq;
        !           308: 
        !           309:        /* pp1 runs through the list of all processes */
        !           310:        while ((pp1=pp1->p_nforw) != &procq) {
        !           311: 
        !           312:                /* if pp1 points to parent of the current process...*/
        !           313:                if (pp1->p_pid == pp->p_ppid) {
        !           314:                        parent = pp1;   /* Remember our parent.  */
        !           315:                        if (ASLEEP(pp1) && pp1->p_event==(char *)pp1)
        !           316:                                wakeup((char *)pp1);
        !           317:                }
        !           318: 
        !           319:                /* if pp1 points to child of the current process...*/
        !           320:                if (pp1->p_ppid == pp->p_pid) {
        !           321:                        pp1->p_ppid = 1;
        !           322:                        if (pp1->p_state == PSDEAD)
        !           323:                                wakeup((char *)eprocp);
        !           324:                        if (pp1->p_flags&PFTRAC)
        !           325:                                wakeup((char *)&pts.pt_req);
        !           326:                }
        !           327:        }
        !           328: 
        !           329:        /*
        !           330:         * Mark us as dead and give up the processor forever.
        !           331:         */
        !           332:        pp->p_exit = s;
        !           333:        pp->p_state = PSDEAD;
        !           334: 
        !           335:        /*
        !           336:         * If this is a process group leader, inform all members of the group
        !           337:         * of the recent death with a HUP signal.
        !           338:         */
        !           339:        if (pp->p_group == pp->p_pid)
        !           340:                ukill(-pp->p_pid, SIGHUP);
        !           341: 
        !           342:        /*
        !           343:         * If the parent is ignoring SIGCLD, 
        !           344:         * remove the zombie right away.
        !           345:         */
        !           346: 
        !           347:        if (parent == NULL)
        !           348:                panic ("%d (@ %x) has no parent!\n", SELF->p_pid, SELF);
        !           349: 
        !           350:        if ((proc_signal_misc (parent) & __SF_NOCLDWAIT) != 0) {
        !           351:                /*
        !           352:                 * The parent has requested that no zombie processes be
        !           353:                 * created out of childen.
        !           354:                 */
        !           355: 
        !           356:                parent->p_cutime += pp->p_utime + pp->p_cutime;
        !           357:                parent->p_cstime += pp->p_stime + pp->p_cstime;
        !           358:                relproc (pp);
        !           359:        } else {
        !           360:                /*
        !           361:                 * Send parent a notification of our demise.
        !           362:                 */
        !           363:                __siginfo_t     sigchld;
        !           364: 
        !           365:                sigchld.__si_signo = SIGCHLD;
        !           366:                sigchld.__si_errno = 0;
        !           367:                if (__WIFEXITED (s)) {
        !           368:                        sigchld.__si_code = __CLD_EXITED;
        !           369:                        sigchld.__si_status = __WEXITSTATUS (s);
        !           370:                } else {
        !           371:                        sigchld.__si_code = __WCOREDUMP (s) ? __CLD_DUMPED :
        !           372:                                                              __CLD_KILLED;
        !           373:                        sigchld.__si_status = __WTERMSIG (s);
        !           374:                }
        !           375:                sigchld.__si_pid = SELF->p_pid;
        !           376:                proc_send_signal (parent, & sigchld);
        !           377:        }
        !           378: 
        !           379:        dispatch();
        !           380: }
        !           381: 
        !           382: /*
        !           383:  * x_sleep()
        !           384:  *
        !           385:  * Surrender CPU while awaiting some event or resource.
        !           386:  *
        !           387:  * Arguments:
        !           388:  *     event:          key value; so wakeup() can find this sleep
        !           389:  *     schedPri:       prilo/primed/prihi/pritape/pritty/pridisk/prinet
        !           390:  *                     just copied into proc struct for scheduler to use.
        !           391:  *                     (see sys/v_types.h)
        !           392:  *     sleepPri:       slpriNoSig      - signals may not interrupt sleep
        !           393:  *                     slpriSigLjmp    - signals cause longjmp (EINTR)
        !           394:  *                     slpriSigCatch   - signals are caught
        !           395:  *                     (see sys/sched.h)
        !           396:  *     reason:         up to 10 chars of text for ps command "event"
        !           397:  *
        !           398:  * Return values:
        !           399:  *     PROCESS_NORMAL_WAKE     wakeup received
        !           400:  *     PROCESS_SIGNALLED       signal (other than SIGSTOP/SIGCONT) received
        !           401:  *     PROCESS_CONTINUED       SIGSTOP/SIGCONT (unimplemented now)
        !           402:  *
        !           403:  * If longjmp occurs, won't return from x_sleep!
        !           404:  */
        !           405: 
        !           406: __sleep_t
        !           407: x_sleep(event, schedPri, sleepPri, reason)
        !           408: char * event;
        !           409: int schedPri;
        !           410: int sleepPri;
        !           411: char * reason;
        !           412: {
        !           413:        int i;
        !           414:        register PROC *bp;
        !           415:        register PROC *fp;
        !           416:        register PROC *pp;
        !           417:        register int s;
        !           418: 
        !           419:        /*
        !           420:         * The descriptive string may be at most 10 characters long.
        !           421:         * It will only be NUL terminated if it has 9 or fewer characters.
        !           422:         */
        !           423:        for (i = 0; i < U_SLEEP_LEN; ++i) {
        !           424:                if ('\0' == (u.u_sleep[i] = reason[i])) {
        !           425:                        break;
        !           426:                }
        !           427:        }
        !           428: 
        !           429:        pp = SELF;
        !           430: 
        !           431:        /*
        !           432:         * Get ready to go to sleep and do so.
        !           433:         */
        !           434:        s = sphi();
        !           435:        pp->p_state = (sleepPri == slpriNoSig) ? PSSLEEP : PSSLSIG;
        !           436:        pp->p_schedPri = schedPri;
        !           437:        pp->p_event = event;
        !           438:        fp = &linkq[hash(event)];
        !           439:        bp = fp->p_lback;
        !           440:        pp->p_lforw = fp;
        !           441:        fp->p_lback = pp;
        !           442:        pp->p_lback = bp;
        !           443:        bp->p_lforw = pp;
        !           444:        spl(s);
        !           445: 
        !           446:        /* Here is sleep if signals may *not* interrupt. */
        !           447:        if (sleepPri == slpriNoSig) {
        !           448:                dispatch ();
        !           449:                u.u_sleep [0] = '\0';
        !           450:                return PROCESS_NORMAL_WAKE;
        !           451:        }
        !           452: 
        !           453:        /* Here is sleep if signals *may* interrupt. */
        !           454:        /* Don't sleep at all if there is already a signal pending. */
        !           455: 
        !           456:        if (curr_signal_pending () == 0) {
        !           457:                dispatch ();
        !           458:                u.u_sleep [0] = '\0';
        !           459:                if (curr_signal_pending () == 0)
        !           460:                        return PROCESS_NORMAL_WAKE;
        !           461:        }
        !           462: 
        !           463:        /* The process has been interrupted from sleep by a signal. */
        !           464: 
        !           465:        if (sleepPri == slpriSigCatch)
        !           466:                return PROCESS_SIGNALLED;
        !           467: 
        !           468:        /* Do longjmp to beginning of system call. */
        !           469:        T_HAL(8, printf("[%d]Ljmps ", SELF->p_pid));
        !           470:        sphi();
        !           471:        envrest(&u.u_sigenv);
        !           472: }
        !           473: 
        !           474: /*
        !           475:  * Defer function to wake up all processes sleeping on the event `e'.
        !           476:  */
        !           477: wakeup(e)
        !           478: char *e;
        !           479: {
        !           480:        void dwakeup();
        !           481: 
        !           482: #ifdef TRACER
        !           483:        /*
        !           484:         * In diagnostic kernel, keep return addr on queue as well.
        !           485:         */
        !           486:        int *r=(int*)(&e);
        !           487:        defer0(dwakeup, e, *(r-1));
        !           488: #else
        !           489:        defer(dwakeup, e);
        !           490: #endif
        !           491: }
        !           492: 
        !           493: /*
        !           494:  * Wake up all processes sleeping on "event".
        !           495:  */
        !           496: void
        !           497: dwakeup(event)
        !           498: char *event;
        !           499: {
        !           500:        register PROC *pp;
        !           501:        register PROC *pp1;
        !           502:        register int s;
        !           503: 
        !           504:        /*
        !           505:         * Identify event queue to check.
        !           506:         * Disable interrupts.
        !           507:         */
        !           508:        pp1 = &linkq[hash(event)];
        !           509:        pp = pp1;
        !           510:        s = sphi();
        !           511: 
        !           512:        /*
        !           513:         * Traverse doubly-linked circular event-queue.
        !           514:         */
        !           515:        while ((pp = pp->p_lforw) != pp1) {
        !           516: 
        !           517:                /*
        !           518:                 * Process is waiting on event 'event'.
        !           519:                 */
        !           520:                if (pp->p_event == event) {
        !           521:                        /*
        !           522:                         * Remove process from event queue.
        !           523:                         * Update process priority.
        !           524:                         * Insert process into run queue.
        !           525:                         */
        !           526:                        pp->p_lback->p_lforw = pp->p_lforw;
        !           527:                        pp->p_lforw->p_lback = pp->p_lback;
        !           528:                        setrun(pp);
        !           529: 
        !           530:                        /*
        !           531:                         * Enable interrupts.
        !           532:                         * Restart search at start of event queue.
        !           533:                         * Disable interrupts.
        !           534:                         */
        !           535:                        spl(s);
        !           536:                        pp = pp1;
        !           537:                        s = sphi();
        !           538:                }
        !           539:        }
        !           540:        spl(s);
        !           541: }
        !           542: 
        !           543: /*
        !           544:  * Select next process for execution, working backward from iprocp.
        !           545:  * If it is not the idle process, delete it from the run queue.
        !           546:  * If it is not the current process, consave the current process and
        !           547:  * conrest the selected process.
        !           548:  */
        !           549: dispatch()
        !           550: {
        !           551:        register PROC *pp;
        !           552:        register int s;
        !           553: 
        !           554:        s = sphi();
        !           555:        pp = iprocp->p_lback;
        !           556:        if (pp != iprocp) {
        !           557:                pp->p_lforw->p_lback = pp->p_lback;
        !           558:                pp->p_lback->p_lforw = pp->p_lforw;
        !           559:        }
        !           560:        spl(s);
        !           561: 
        !           562:        quantum = NCRTICK;
        !           563:        disflag = 0;
        !           564:        if (pp != SELF) {
        !           565:                /*
        !           566:                 * Consave() returns twice.
        !           567:                 * 1st time is after our context is saved in u.u_syscon,
        !           568:                 *      whereupon we should restore other proc's context.
        !           569:                 * 2nd time is after our context is restored by another proc.
        !           570:                 * Conrest() forces a context switch to a new process.
        !           571:                 */
        !           572:                s = sphi ();
        !           573:                SELF = pp;
        !           574:                if (consave (& u.u_syscon) == 0) {
        !           575:                        conrest (* pp->p_segp [SIUSERP]->s_vmem,
        !           576:                                 & u.u_syscon);
        !           577:                }
        !           578: 
        !           579:                if (SELF->p_pid) {      /* init is special! */
        !           580:                        ndpConRest ();
        !           581:                        segload ();
        !           582:                }
        !           583: 
        !           584:                spl (s);
        !           585:        }
        !           586: }
        !           587: 
        !           588: /*
        !           589:  * Add a process to the run queue, just forward of iprocp.
        !           590:  * This routine must be called at high priority.
        !           591:  */
        !           592: setrun(pp)
        !           593: register PROC *pp;
        !           594: {
        !           595:        pp->p_lback = iprocp;
        !           596:        pp->p_lforw = iprocp->p_lforw;
        !           597:        pp->p_lback->p_lforw = pp;
        !           598:        pp->p_lforw->p_lback = pp;
        !           599:        pp->p_state = PSRUN;
        !           600: }
        !           601: 
        !           602: /*
        !           603:  * Wait for the gate `g' to unlock, and then lock it.
        !           604:  */
        !           605: lock(g)
        !           606: register GATE g;
        !           607: {
        !           608:        register int s;
        !           609: 
        !           610:        s = sphi ();
        !           611:        while (g->_lock [0]) {
        !           612: #ifdef TRACER
        !           613:                if (g->_lock [0] != 1)
        !           614:                        panic ("Uninitialised gate");
        !           615: #endif
        !           616:                g->_lock [1] = 1;
        !           617:                x_sleep ((char *) g, primed, slpriNoSig, "lock");
        !           618:                /* Waiting for a gate to unlock.  */
        !           619:        }
        !           620:        g->_lock [0] = 1;
        !           621:        __GATE_LOCK_COUNT (g);
        !           622:        spl (s);
        !           623: }
        !           624: 
        !           625: /*
        !           626:  * Unlock the gate `g'.
        !           627:  */
        !           628: unlock(g)
        !           629: register GATE g;
        !           630: {
        !           631: #ifdef TRACER
        !           632:        if (g->_lock [0] == 0)
        !           633:                panic ("Gate not locked!");
        !           634: #endif
        !           635:        g->_lock [0] = 0;
        !           636:        if (g->_lock [1]) {
        !           637: #ifdef TRACER
        !           638:                if (g->_lock [1] != 1)
        !           639:                        panic ("Uninitialised gate");
        !           640: #endif
        !           641:                g->_lock [1] = 0;
        !           642:                disflag = 1;
        !           643:                wakeup ((char *)g);
        !           644:        }
        !           645: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.