|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: eventcount.c ! 31: * Author: Alessandro Forin ! 32: * Date: 10/91 ! 33: * ! 34: * Eventcounters, for user-level drivers synchronization ! 35: * ! 36: */ ! 37: ! 38: ! 39: #include <cpus.h> ! 40: ! 41: #include <mach/machine.h> ! 42: #include <kern/ast.h> ! 43: #include "cpu_number.h" ! 44: #include <kern/lock.h> ! 45: #include <kern/processor.h> ! 46: #include <kern/queue.h> ! 47: #include <kern/sched.h> ! 48: #include <kern/sched_prim.h> ! 49: #include <kern/thread.h> ! 50: ! 51: #include <machine/machspl.h> /* For def'n of splsched() */ ! 52: ! 53: #include <kern/eventcount.h> ! 54: ! 55: ! 56: #if NCPUS <= 1 ! 57: void simpler_thread_setrun( ! 58: thread_t th, ! 59: boolean_t may_preempt); /* forward */ ! 60: #endif ! 61: ! 62: #define MAX_EVCS 10 /* xxx for now */ ! 63: evc_t all_eventcounters[MAX_EVCS]; ! 64: ! 65: /* ! 66: * Initialization ! 67: */ ! 68: void ! 69: evc_init(evc_t ev) ! 70: { ! 71: int i; ! 72: ! 73: bzero((char*)ev, sizeof(*ev)); ! 74: ! 75: /* keep track of who is who */ ! 76: for (i = 0; i < MAX_EVCS; i++) ! 77: if (all_eventcounters[i] == 0) break; ! 78: if (i == MAX_EVCS) { ! 79: printf("Too many eventcounters\n"); ! 80: return; ! 81: } ! 82: ! 83: all_eventcounters[i] = ev; ! 84: ev->ev_id = i; ! 85: ev->sanity = ev; ! 86: ev->waiting_thread = THREAD_NULL; ! 87: simple_lock_init(&ev->lock); ! 88: } ! 89: ! 90: /* ! 91: * Finalization ! 92: */ ! 93: void ! 94: evc_destroy(evc_t ev) ! 95: { ! 96: evc_signal(ev); ! 97: ev->sanity = 0; ! 98: if (all_eventcounters[ev->ev_id] == ev) ! 99: all_eventcounters[ev->ev_id] = 0; ! 100: ev->ev_id = -1; ! 101: } ! 102: ! 103: /* ! 104: * Thread termination. ! 105: * HORRIBLE. This stuff needs to be fixed. ! 106: */ ! 107: void evc_notify_abort(thread_t thread) ! 108: { ! 109: int i; ! 110: evc_t ev; ! 111: int s = splsched(); ! 112: for (i = 0; i < MAX_EVCS; i++) { ! 113: ev = all_eventcounters[i]; ! 114: if (ev) { ! 115: simple_lock(&ev->lock); ! 116: if (ev->waiting_thread == thread) ! 117: { ! 118: ev->waiting_thread = 0; ! 119: /* Removal of a waiting thread has to bump the count by one */ ! 120: ev->count++; ! 121: } ! 122: simple_unlock(&ev->lock); ! 123: } ! 124: } ! 125: splx(s); ! 126: } ! 127: ! 128: #ifdef CONTINUATIONS ! 129: /* ! 130: * Just so that we return success, and give ! 131: * up the stack while blocked ! 132: */ ! 133: static void ! 134: evc_continue(void) ! 135: { ! 136: thread_syscall_return(KERN_SUCCESS); ! 137: /* NOTREACHED */ ! 138: } ! 139: #else /* not CONTINUATIONS */ ! 140: #define evc_continue 0 ! 141: #endif /* not CONTINUATIONS */ ! 142: ! 143: /* ! 144: * User-trappable ! 145: */ ! 146: kern_return_t evc_wait(natural_t ev_id) ! 147: { ! 148: spl_t s; ! 149: kern_return_t ret; ! 150: evc_t ev; ! 151: ! 152: if ((ev_id >= MAX_EVCS) || ! 153: ((ev = all_eventcounters[ev_id]) == 0) || ! 154: (ev->ev_id != ev_id) || (ev->sanity != ev)) ! 155: return KERN_INVALID_ARGUMENT; ! 156: ! 157: s = splsched(); ! 158: simple_lock(&ev->lock); ! 159: /* ! 160: * The values assumed by the "count" field are ! 161: * as follows: ! 162: * 0 At initialization time, and with no ! 163: * waiting thread means no events pending; ! 164: * with waiting thread means the event ! 165: * was signalled and the thread not yet resumed ! 166: * -1 no events, there must be a waiting thread ! 167: * N>0 no waiting thread means N pending, ! 168: * with waiting thread N-1 pending. ! 169: * ! 170: */ ! 171: if (ev->count > 0) { ! 172: ev->count--; ! 173: ret = KERN_SUCCESS; ! 174: } else { ! 175: if (ev->waiting_thread == THREAD_NULL) { ! 176: ev->count--; ! 177: ev->waiting_thread = current_thread(); ! 178: assert_wait((event_t) 0, TRUE); /* ifnot race */ ! 179: simple_unlock(&ev->lock); ! 180: thread_block(evc_continue); ! 181: return KERN_SUCCESS; ! 182: } ! 183: ret = KERN_NO_SPACE; /* XX */ ! 184: } ! 185: simple_unlock(&ev->lock); ! 186: splx(s); ! 187: return ret; ! 188: } ! 189: ! 190: /* ! 191: * User-trappable ! 192: */ ! 193: kern_return_t evc_wait_clear(natural_t ev_id) ! 194: { ! 195: spl_t s; ! 196: kern_return_t ret; ! 197: evc_t ev; ! 198: ! 199: if ((ev_id >= MAX_EVCS) || ! 200: ((ev = all_eventcounters[ev_id]) == 0) || ! 201: (ev->ev_id != ev_id) || (ev->sanity != ev)) ! 202: return KERN_INVALID_ARGUMENT; ! 203: ! 204: s = splsched(); ! 205: simple_lock(&ev->lock); ! 206: ! 207: /* ! 208: * The values assumed by the "count" field are ! 209: * as follows: ! 210: * 0 At initialization time, and with no ! 211: * waiting thread means no events pending; ! 212: * with waiting thread means the event ! 213: * was signalled and the thread not yet resumed ! 214: * -1 no events, there must be a waiting thread ! 215: * N>0 no waiting thread means N pending, ! 216: * with waiting thread N-1 pending. ! 217: * ! 218: */ ! 219: /* ! 220: * Note that we always clear count before blocking. ! 221: */ ! 222: if (ev->waiting_thread == THREAD_NULL) { ! 223: ev->count = -1; ! 224: ev->waiting_thread = current_thread(); ! 225: assert_wait((event_t) 0, TRUE); /* ifnot race */ ! 226: simple_unlock(&ev->lock); ! 227: thread_block(evc_continue); ! 228: /* NOTREACHED */ ! 229: } ! 230: ! 231: simple_unlock(&ev->lock); ! 232: splx(s); ! 233: ret = KERN_NO_SPACE; /* XX */ ! 234: } ! 235: ! 236: /* ! 237: * Called exclusively from interrupt context ! 238: */ ! 239: void ! 240: evc_signal(evc_t ev) ! 241: { ! 242: register volatile thread_t thread; ! 243: register int state; ! 244: spl_t s; ! 245: if (ev->sanity != ev) ! 246: return; ! 247: ! 248: s = splsched(); ! 249: simple_lock(&ev->lock); ! 250: ev->count++; ! 251: if (thread = ev->waiting_thread, thread != THREAD_NULL) ! 252: { ! 253: ev->waiting_thread = 0; ! 254: ! 255: #if (NCPUS > 1) ! 256: retry: ! 257: while((thread->state & TH_RUN) || thread->lock.lock_data) ! 258: ; ! 259: #endif ! 260: thread_lock(thread); ! 261: ! 262: /* make thread runnable on this processor */ ! 263: /* taken from clear_wait */ ! 264: switch ((state = thread->state) & TH_SCHED_STATE) ! 265: { ! 266: case TH_WAIT | TH_SUSP | TH_UNINT: ! 267: case TH_WAIT | TH_UNINT: ! 268: case TH_WAIT: ! 269: /* ! 270: * Sleeping and not suspendable - put ! 271: * on run queue. ! 272: */ ! 273: thread->state = (state &~ TH_WAIT) | TH_RUN; ! 274: thread_unlock(thread); ! 275: #if NCPUS > 1 ! 276: thread_setrun(thread, TRUE); ! 277: #else ! 278: simpler_thread_setrun(thread, TRUE); ! 279: #endif ! 280: break; ! 281: ! 282: case TH_RUN | TH_WAIT: ! 283: #if (NCPUS > 1) ! 284: /* ! 285: * Legal on MP: between assert_wait() ! 286: * and thread_block(), in evc_wait() above. ! 287: * ! 288: * Mmm. Maybe don't need now that the while(..) check is ! 289: * done before the thread lock is grabbed..... ! 290: */ ! 291: thread_unlock(thread); ! 292: goto retry; ! 293: #else ! 294: /*FALLTHROUGH*/ ! 295: #endif ! 296: case TH_WAIT | TH_SUSP: ! 297: case TH_RUN | TH_WAIT | TH_SUSP: ! 298: case TH_RUN | TH_WAIT | TH_UNINT: ! 299: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 300: ! 301: /* ! 302: * Either already running, or suspended. ! 303: * Just clear the wait. ! 304: */ ! 305: thread->state = state &~ TH_WAIT; ! 306: thread_unlock(thread); ! 307: break; ! 308: ! 309: default: ! 310: /* ! 311: * Not waiting. ! 312: */ ! 313: panic("evc_signal.3"); ! 314: thread_unlock(thread); ! 315: break; ! 316: } ! 317: } ! 318: ! 319: simple_unlock(&ev->lock); ! 320: splx(s); ! 321: } ! 322: ! 323: #if NCPUS <= 1 ! 324: /* ! 325: * The scheduler is too messy for my old little brain ! 326: */ ! 327: void ! 328: simpler_thread_setrun( ! 329: thread_t th, ! 330: boolean_t may_preempt) ! 331: { ! 332: register struct run_queue *rq; ! 333: register whichq; ! 334: ! 335: /* ! 336: * XXX should replace queue with a boolean in this case. ! 337: */ ! 338: if (default_pset.idle_count > 0) { ! 339: processor_t processor; ! 340: ! 341: processor = (processor_t) queue_first(&default_pset.idle_queue); ! 342: queue_remove(&default_pset.idle_queue, processor, ! 343: processor_t, processor_queue); ! 344: default_pset.idle_count--; ! 345: processor->next_thread = th; ! 346: processor->state = PROCESSOR_DISPATCHING; ! 347: return; ! 348: } ! 349: rq = &(master_processor->runq); ! 350: ast_on(cpu_number(), AST_BLOCK); ! 351: ! 352: whichq = (th)->sched_pri; ! 353: simple_lock(&(rq)->lock); /* lock the run queue */ ! 354: enqueue_head(&(rq)->runq[whichq], (queue_entry_t) (th)); ! 355: ! 356: if (whichq < (rq)->low || (rq)->count == 0) ! 357: (rq)->low = whichq; /* minimize */ ! 358: (rq)->count++; ! 359: #ifdef MIGRATING_THREADS ! 360: (th)->shuttle.runq = (rq); ! 361: #else ! 362: (th)->runq = (rq); ! 363: #endif ! 364: simple_unlock(&(rq)->lock); ! 365: ! 366: /* ! 367: * Turn off first_quantum to allow context switch. ! 368: */ ! 369: current_processor()->first_quantum = FALSE; ! 370: } ! 371: #endif /* NCPUS > 1 */ ! 372:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.