/* Copyright (C) 1986 Sun Microsystems Inc. */ /* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify this source code without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC. * AND IS LICENSED TO SUNSOFT, INC., A SUBSIDIARY OF SUN MICROSYSTEMS, INC. * SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY * OF SUCH SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT * EXPRESS OR IMPLIED WARRANTY OF ANY KIND. SUN MICROSYSTEMS, INC. DISCLAIMS * ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN * NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY. * * This source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS * SOURCE CODE OR ANY PART THEREOF. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef lint SCCSID(@(#) schedule.c 1.1 94/10/31 Copyr 1986 Sun Micro); #endif lint #ifndef SHAREDLIB int __LwpLibInit = 0; /* non-zero if initialized */ #endif SHAREDLIB int __HighPrio; /* highest priority current runnable lwp */ lwp_t Nullproc; /* have something for lwp_errno until init */ lwp_t *__Curproc = &Nullproc; /* the current running process */ qheader_t *__RunQ = QHNULL; /* set of run queues (1 per priority) */ int __MaxPrio = MINPRIO; /* highest available scheduling priority */ int __UniqId = 0; /* unique id for locks and keys */ /* * PRIMITIVES contained herein: * pod_setmaxpri(prio) * pod_getmaxsize() * pod_getmaxpri() */ /* * pod_getmaxsize() -- PRIMITIVE. * Return maximum possible size of pod. */ int pod_getmaxsize() { return (MAXPRIO); } /* * pod_getmaxpri() -- PRIMITIVE. * Return current highest legal prio for pod. */ int pod_getmaxpri() { return (__MaxPrio); } /* * pod_setmaxpri -- PRIMITIVE. * set maximum pod size. Visible priorities range from MINPRIO to __Maxprio * so there are a total of __MaxPrio+1 priorities since we always allocate * a priority (NUGPRIO) for the library. In reality, priorities * range from [NUGPRIO .. __MaxPrio]. */ int pod_setmaxpri(prio) int prio; /* new number of scheduling priorities */ { qheader_t *tempq = QHNULL; register int i; if (__LwpLibInit == 0) { /* initialize by hand to avoid 2 MEM_ALLOCS */ __MaxPrio = prio; __LwpLibInit++; __lwp_init(); return (0); } LOCK(); ERROR((prio > MAXPRIO), LE_NOROOM); ERROR((prio < __MaxPrio), LE_INVALIDARG); if (prio == __MaxPrio) { UNLOCK(); return (0); } tempq = (qheader_t *)MEM_ALLOC(sizeof (qheader_t) * (prio + 1)); if ((tempq == QHNULL) || (__RunQ == QHNULL)) { __panic("Can't create pod"); /* NOTREACHED */ } /* copy RunQ to tempq */ for (i = NUGPRIO; i <= __MaxPrio; i++) { tempq[i].hq_head = __RunQ[i].hq_head; tempq[i].hq_tail = __RunQ[i].hq_tail; } MEM_FREE(__RunQ, (sizeof (qheader_t) * (__MaxPrio + 1))); __MaxPrio = prio; __RunQ = tempq; UNLOCK(); for (i = 0; i < __SlaveThreads; i++) { if (!SAMETHREAD(__Slaves[i], THREADNULL)) (void)lwp_setpri(__Slaves[i], __MaxPrio); } return (0); } /* * __lwp_init: initialize library. * N.B. Order of initialization is important. */ void __lwp_init() { thread_t idlethread; extern void __init_util(); INIT_QUEUE(&Nullproc.lwp_ctx); Nullproc.lwp_prio = NUGPRIO; __RunQ = (qheader_t *)MEM_ALLOC(sizeof (qheader_t) * (__MaxPrio + 1)); __HighPrio = NUGPRIO; __init_lwp(); __init_sig(); __init_asynch(); __init_agent(); __init_msg(); __init_mon(); __init_exc(); __init_cv(); __init_clock(); __init_machdep(); __init_ctx(); __init_stks(); __init_util(); __maincreate(); /* don't use LWPSERVER flag: this guy runs at lowest priority */ (void)lwp_create(&idlethread, __idle, MINPRIO, 0, (stkalign_t *)&__IdleStack[IDLESTACK], 0); /* give idle lower than legal (for client) priority */ REMX_ITEM(&__RunQ[MINPRIO], idlethread.thread_id); INS_QUEUE(&__RunQ[NUGPRIO], idlethread.thread_id); ((lwp_t *)(idlethread.thread_id))->lwp_prio = NUGPRIO; ((lwp_t *)(idlethread.thread_id))->lwp_lock = UNIQUEID(); } /* * Scheduler loop for the set of lwps. * Find the highest priority runnable lwp and set it going. * Note that __HighPrio can be the priority of the process that * last did a WAIT but may not be the priority of the next * eligible process. In the worst case, since the process that did the WAIT * was at the highest priority currently, only a priority less than * __HighPrio can be eligible. * If returning from an interrupt to the same process, it is probably cheaper * to restore the saved context than to return back through the call * chain to the rti. * We had to always save full context on interrupt because we didn't know * in advance if this would be the case. */ void __schedule() { register int i; register lwp_t *oldproc = __Curproc; register lwp_t *newproc; register qheader_t *rq; LOCK(); LWPTRACE(tr_SCHEDULE, 5, ("scheduling\n")); for (i = __HighPrio; i >= NUGPRIO; i--, __HighPrio--) { rq = &__RunQ[i]; if (!ISEMPTYQ(rq)) { newproc = __Curproc = (lwp_t *)FIRSTQ(rq); if (((oldproc != LWPNULL) && !ISEMPTYQ(&oldproc->lwp_ctx)) || !ISEMPTYQ(&newproc->lwp_ctx)) { __ctx_change(oldproc, newproc); } LWPTRACE(tr_SCHEDULE, 2, ("about to schedule %x\n", (int)__Curproc)); if (!newproc->lwp_full && (__SigLocked == 0)) { /* * do a simple context switch (only non-volatile * registers, no temps or sr.) * This is the case on a yield or where * there is no asynchronous event indirectly * responsible for the context switch (i.e., * waiting for a monitor or a message). */ LWPTRACE(tr_SCHEDULE, 2, ("swtch call\n")); CSWTCH(); } else { /* * do a full context switch, restoring temps, sr, * etc., as needed. */ LWPTRACE(tr_SCHEDULE, 2, ("full swtch call\n")); __full_swtch(); } __panic("return from swtch"); /* NOTREACHED */ } } UNLOCK(); LWPTRACE(tr_SCHEDULE, 1, ("schedule exiting\n")); HALT(); /* NOTREACHED */ }