|
|
1.1 ! root 1: /* ! 2: * Linux scheduling support. ! 3: * ! 4: * Copyright (C) 1996 The University of Utah and the Computer Systems ! 5: * Laboratory at the University of Utah (CSL) ! 6: * ! 7: * This program is free software; you can redistribute it and/or modify ! 8: * it under the terms of the GNU General Public License as published by ! 9: * the Free Software Foundation; either version 2, or (at your option) ! 10: * any later version. ! 11: * ! 12: * This program is distributed in the hope that it will be useful, ! 13: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: * GNU General Public License for more details. ! 16: * ! 17: * You should have received a copy of the GNU General Public License ! 18: * along with this program; if not, write to the Free Software ! 19: * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 20: * ! 21: * Author: Shantanu Goel, University of Utah CSL ! 22: */ ! 23: ! 24: /* ! 25: * linux/kernel/sched.c ! 26: * ! 27: * Copyright (C) 1991, 1992 Linus Torvalds ! 28: */ ! 29: ! 30: #include <sys/types.h> ! 31: #include <machine/spl.h> ! 32: ! 33: #include <mach/boolean.h> ! 34: ! 35: #include <kern/thread.h> ! 36: #include <kern/sched_prim.h> ! 37: ! 38: #define MACH_INCLUDE ! 39: #include <linux/sched.h> ! 40: #include <linux/timer.h> ! 41: #include <linux/fs.h> ! 42: #include <linux/blkdev.h> ! 43: #include <linux/interrupt.h> ! 44: ! 45: #include <asm/system.h> ! 46: #include <asm/atomic.h> ! 47: ! 48: int securelevel = 0; ! 49: ! 50: extern void *alloc_contig_mem (unsigned, unsigned, unsigned, vm_page_t *); ! 51: extern void free_contig_mem (vm_page_t); ! 52: extern spl_t splhigh (void); ! 53: extern spl_t splx (spl_t); ! 54: extern void linux_soft_intr (void); ! 55: extern int issig (void); ! 56: extern int printf (const char *, ...); ! 57: extern int linux_auto_config; ! 58: ! 59: static void timer_bh (void); ! 60: ! 61: DECLARE_TASK_QUEUE (tq_timer); ! 62: DECLARE_TASK_QUEUE (tq_immediate); ! 63: DECLARE_TASK_QUEUE (tq_scheduler); ! 64: ! 65: static struct wait_queue **auto_config_queue; ! 66: ! 67: static inline void ! 68: handle_soft_intr (void) ! 69: { ! 70: if (bh_active & bh_mask) ! 71: { ! 72: intr_count = 1; ! 73: linux_soft_intr (); ! 74: intr_count = 0; ! 75: } ! 76: } ! 77: ! 78: static void ! 79: tqueue_bh (void) ! 80: { ! 81: run_task_queue(&tq_timer); ! 82: } ! 83: ! 84: static void ! 85: immediate_bh (void) ! 86: { ! 87: run_task_queue (&tq_immediate); ! 88: } ! 89: ! 90: void ! 91: add_wait_queue (struct wait_queue **q, struct wait_queue *wait) ! 92: { ! 93: unsigned long flags; ! 94: ! 95: if (! linux_auto_config) ! 96: { ! 97: save_flags (flags); ! 98: cli (); ! 99: assert_wait ((event_t) q, FALSE); ! 100: restore_flags (flags); ! 101: return; ! 102: } ! 103: ! 104: if (auto_config_queue) ! 105: printf ("add_wait_queue: queue not empty\n"); ! 106: auto_config_queue = q; ! 107: } ! 108: ! 109: void ! 110: remove_wait_queue (struct wait_queue **q, struct wait_queue *wait) ! 111: { ! 112: unsigned long flags; ! 113: ! 114: if (! linux_auto_config) ! 115: { ! 116: save_flags (flags); ! 117: thread_wakeup ((event_t) q); ! 118: restore_flags (flags); ! 119: return; ! 120: } ! 121: ! 122: auto_config_queue = NULL; ! 123: } ! 124: ! 125: static inline int ! 126: waking_non_zero (struct semaphore *sem) ! 127: { ! 128: int ret; ! 129: unsigned long flags; ! 130: ! 131: get_buzz_lock (&sem->lock); ! 132: save_flags (flags); ! 133: cli (); ! 134: ! 135: if ((ret = (sem->waking > 0))) ! 136: sem->waking--; ! 137: ! 138: restore_flags (flags); ! 139: give_buzz_lock (&sem->lock); ! 140: return ret; ! 141: } ! 142: ! 143: void ! 144: __up (struct semaphore *sem) ! 145: { ! 146: atomic_inc (&sem->waking); ! 147: wake_up (&sem->wait); ! 148: } ! 149: ! 150: int ! 151: __do_down (struct semaphore *sem, int task_state) ! 152: { ! 153: unsigned long flags; ! 154: int ret = 0; ! 155: int s; ! 156: ! 157: if (!linux_auto_config) ! 158: { ! 159: save_flags (flags); ! 160: s = splhigh (); ! 161: for (;;) ! 162: { ! 163: if (waking_non_zero (sem)) ! 164: break; ! 165: ! 166: if (task_state == TASK_INTERRUPTIBLE && issig ()) ! 167: { ! 168: ret = -LINUX_EINTR; ! 169: atomic_inc (&sem->count); ! 170: break; ! 171: } ! 172: ! 173: assert_wait ((event_t) &sem->wait, ! 174: task_state == TASK_INTERRUPTIBLE ? TRUE : FALSE); ! 175: splx (s); ! 176: schedule (); ! 177: s = splhigh (); ! 178: } ! 179: splx (s); ! 180: restore_flags (flags); ! 181: return ret; ! 182: } ! 183: ! 184: while (!waking_non_zero (sem)) ! 185: { ! 186: if (task_state == TASK_INTERRUPTIBLE && issig ()) ! 187: { ! 188: ret = -LINUX_EINTR; ! 189: atomic_inc (&sem->count); ! 190: break; ! 191: } ! 192: schedule (); ! 193: } ! 194: ! 195: return ret; ! 196: } ! 197: ! 198: void ! 199: __down (struct semaphore *sem) ! 200: { ! 201: __do_down(sem, TASK_UNINTERRUPTIBLE); ! 202: } ! 203: ! 204: int ! 205: __down_interruptible (struct semaphore *sem) ! 206: { ! 207: return __do_down (sem, TASK_INTERRUPTIBLE); ! 208: } ! 209: ! 210: void ! 211: __sleep_on (struct wait_queue **q, int state) ! 212: { ! 213: unsigned long flags; ! 214: ! 215: if (!q) ! 216: return; ! 217: save_flags (flags); ! 218: if (!linux_auto_config) ! 219: { ! 220: assert_wait ((event_t) q, state == TASK_INTERRUPTIBLE ? TRUE : FALSE); ! 221: sti (); ! 222: schedule (); ! 223: restore_flags (flags); ! 224: return; ! 225: } ! 226: ! 227: add_wait_queue (q, NULL); ! 228: sti (); ! 229: while (auto_config_queue) ! 230: schedule (); ! 231: restore_flags (flags); ! 232: } ! 233: ! 234: void ! 235: sleep_on (struct wait_queue **q) ! 236: { ! 237: __sleep_on (q, TASK_UNINTERRUPTIBLE); ! 238: } ! 239: ! 240: void ! 241: interruptible_sleep_on (struct wait_queue **q) ! 242: { ! 243: __sleep_on (q, TASK_INTERRUPTIBLE); ! 244: } ! 245: ! 246: void ! 247: wake_up (struct wait_queue **q) ! 248: { ! 249: unsigned long flags; ! 250: ! 251: if (! linux_auto_config) ! 252: { ! 253: if (q != &wait_for_request) /* ??? by OKUJI Yoshinori. */ ! 254: { ! 255: save_flags (flags); ! 256: thread_wakeup ((event_t) q); ! 257: restore_flags (flags); ! 258: } ! 259: return; ! 260: } ! 261: ! 262: if (auto_config_queue == q) ! 263: auto_config_queue = NULL; ! 264: } ! 265: ! 266: void ! 267: __wait_on_buffer (struct buffer_head *bh) ! 268: { ! 269: unsigned long flags; ! 270: ! 271: save_flags (flags); ! 272: if (! linux_auto_config) ! 273: { ! 274: while (1) ! 275: { ! 276: cli (); ! 277: run_task_queue (&tq_disk); ! 278: if (! buffer_locked (bh)) ! 279: break; ! 280: bh->b_wait = (struct wait_queue *) 1; ! 281: assert_wait ((event_t) bh, FALSE); ! 282: sti (); ! 283: schedule (); ! 284: } ! 285: restore_flags (flags); ! 286: return; ! 287: } ! 288: ! 289: sti (); ! 290: while (buffer_locked (bh)) ! 291: { ! 292: run_task_queue (&tq_disk); ! 293: schedule (); ! 294: } ! 295: restore_flags (flags); ! 296: } ! 297: ! 298: void ! 299: unlock_buffer (struct buffer_head *bh) ! 300: { ! 301: unsigned long flags; ! 302: ! 303: save_flags (flags); ! 304: cli (); ! 305: clear_bit (BH_Lock, &bh->b_state); ! 306: if (bh->b_wait && ! linux_auto_config) ! 307: { ! 308: bh->b_wait = NULL; ! 309: thread_wakeup ((event_t) bh); ! 310: } ! 311: restore_flags (flags); ! 312: } ! 313: ! 314: void ! 315: schedule (void) ! 316: { ! 317: if (intr_count) ! 318: printk ("Aiee: scheduling in interrupt %p\n", ! 319: __builtin_return_address (0)); ! 320: ! 321: handle_soft_intr (); ! 322: run_task_queue (&tq_scheduler); ! 323: ! 324: if (!linux_auto_config) ! 325: thread_block (0); ! 326: } ! 327: ! 328: void ! 329: cdrom_sleep (int t) ! 330: { ! 331: int xxx; ! 332: ! 333: assert_wait ((event_t) &xxx, TRUE); ! 334: thread_set_timeout (t); ! 335: schedule (); ! 336: } ! 337: ! 338: void ! 339: linux_sched_init (void) ! 340: { ! 341: /* ! 342: * Install software interrupt handlers. ! 343: */ ! 344: init_bh (TIMER_BH, timer_bh); ! 345: init_bh (TQUEUE_BH, tqueue_bh); ! 346: init_bh (IMMEDIATE_BH, immediate_bh); ! 347: } ! 348: ! 349: /* ! 350: * Linux timers. ! 351: * ! 352: * Copyright (C) 1996 The University of Utah and the Computer Systems ! 353: * Laboratory at the University of Utah (CSL) ! 354: * ! 355: * This program is free software; you can redistribute it and/or modify ! 356: * it under the terms of the GNU General Public License as published by ! 357: * the Free Software Foundation; either version 2, or (at your option) ! 358: * any later version. ! 359: * ! 360: * This program is distributed in the hope that it will be useful, ! 361: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 362: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 363: * GNU General Public License for more details. ! 364: * ! 365: * You should have received a copy of the GNU General Public License ! 366: * along with this program; if not, write to the Free Software ! 367: * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 368: * ! 369: * Author: Shantanu Goel, University of Utah CSL ! 370: */ ! 371: ! 372: unsigned long volatile jiffies = 0; ! 373: ! 374: /* ! 375: * Mask of active timers. ! 376: */ ! 377: unsigned long timer_active = 0; ! 378: ! 379: /* ! 380: * List of timeout routines. ! 381: */ ! 382: struct timer_struct timer_table[32]; ! 383: ! 384: #define TVN_BITS 6 ! 385: #define TVR_BITS 8 ! 386: #define TVN_SIZE (1 << TVN_BITS) ! 387: #define TVR_SIZE (1 << TVR_BITS) ! 388: #define TVN_MASK (TVN_SIZE - 1) ! 389: #define TVR_MASK (TVR_SIZE - 1) ! 390: ! 391: #define SLOW_BUT_DEBUGGING_TIMERS 0 ! 392: ! 393: struct timer_vec ! 394: { ! 395: int index; ! 396: struct timer_list *vec[TVN_SIZE]; ! 397: }; ! 398: ! 399: struct timer_vec_root ! 400: { ! 401: int index; ! 402: struct timer_list *vec[TVR_SIZE]; ! 403: }; ! 404: ! 405: static struct timer_vec tv5 = ! 406: {0}; ! 407: static struct timer_vec tv4 = ! 408: {0}; ! 409: static struct timer_vec tv3 = ! 410: {0}; ! 411: static struct timer_vec tv2 = ! 412: {0}; ! 413: static struct timer_vec_root tv1 = ! 414: {0}; ! 415: ! 416: static struct timer_vec *const tvecs[] = ! 417: { ! 418: (struct timer_vec *) &tv1, &tv2, &tv3, &tv4, &tv5 ! 419: }; ! 420: ! 421: #define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0])) ! 422: ! 423: static unsigned long timer_jiffies = 0; ! 424: ! 425: static inline void ! 426: insert_timer (struct timer_list *timer, struct timer_list **vec, int idx) ! 427: { ! 428: if ((timer->next = vec[idx])) ! 429: vec[idx]->prev = timer; ! 430: vec[idx] = timer; ! 431: timer->prev = (struct timer_list *) &vec[idx]; ! 432: } ! 433: ! 434: static inline void ! 435: internal_add_timer (struct timer_list *timer) ! 436: { ! 437: /* ! 438: * must be cli-ed when calling this ! 439: */ ! 440: unsigned long expires = timer->expires; ! 441: unsigned long idx = expires - timer_jiffies; ! 442: ! 443: if (idx < TVR_SIZE) ! 444: { ! 445: int i = expires & TVR_MASK; ! 446: insert_timer (timer, tv1.vec, i); ! 447: } ! 448: else if (idx < 1 << (TVR_BITS + TVN_BITS)) ! 449: { ! 450: int i = (expires >> TVR_BITS) & TVN_MASK; ! 451: insert_timer (timer, tv2.vec, i); ! 452: } ! 453: else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) ! 454: { ! 455: int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK; ! 456: insert_timer (timer, tv3.vec, i); ! 457: } ! 458: else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) ! 459: { ! 460: int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK; ! 461: insert_timer (timer, tv4.vec, i); ! 462: } ! 463: else if (expires < timer_jiffies) ! 464: { ! 465: /* can happen if you add a timer with expires == jiffies, ! 466: * or you set a timer to go off in the past ! 467: */ ! 468: insert_timer (timer, tv1.vec, tv1.index); ! 469: } ! 470: else if (idx < 0xffffffffUL) ! 471: { ! 472: int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; ! 473: insert_timer (timer, tv5.vec, i); ! 474: } ! 475: else ! 476: { ! 477: /* Can only get here on architectures with 64-bit jiffies */ ! 478: timer->next = timer->prev = timer; ! 479: } ! 480: } ! 481: ! 482: void ! 483: add_timer (struct timer_list *timer) ! 484: { ! 485: unsigned long flags; ! 486: ! 487: save_flags (flags); ! 488: cli (); ! 489: #if SLOW_BUT_DEBUGGING_TIMERS ! 490: if (timer->next || timer->prev) ! 491: { ! 492: printk ("add_timer() called with non-zero list from %p\n", ! 493: __builtin_return_address (0)); ! 494: goto out; ! 495: } ! 496: #endif ! 497: internal_add_timer (timer); ! 498: #if SLOW_BUT_DEBUGGING_TIMERS ! 499: out: ! 500: #endif ! 501: restore_flags (flags); ! 502: } ! 503: ! 504: static inline int ! 505: detach_timer (struct timer_list *timer) ! 506: { ! 507: int ret = 0; ! 508: struct timer_list *next, *prev; ! 509: ! 510: next = timer->next; ! 511: prev = timer->prev; ! 512: if (next) ! 513: { ! 514: next->prev = prev; ! 515: } ! 516: if (prev) ! 517: { ! 518: ret = 1; ! 519: prev->next = next; ! 520: } ! 521: return ret; ! 522: } ! 523: ! 524: int ! 525: del_timer (struct timer_list *timer) ! 526: { ! 527: int ret; ! 528: unsigned long flags; ! 529: ! 530: save_flags (flags); ! 531: cli (); ! 532: ret = detach_timer (timer); ! 533: timer->next = timer->prev = 0; ! 534: restore_flags (flags); ! 535: return ret; ! 536: } ! 537: ! 538: static inline void ! 539: run_old_timers (void) ! 540: { ! 541: struct timer_struct *tp; ! 542: unsigned long mask; ! 543: ! 544: for (mask = 1, tp = timer_table + 0; mask; tp++, mask += mask) ! 545: { ! 546: if (mask > timer_active) ! 547: break; ! 548: if (!(mask & timer_active)) ! 549: continue; ! 550: if (tp->expires > jiffies) ! 551: continue; ! 552: timer_active &= ~mask; ! 553: tp->fn (); ! 554: sti (); ! 555: } ! 556: } ! 557: ! 558: static inline void ! 559: cascade_timers (struct timer_vec *tv) ! 560: { ! 561: /* cascade all the timers from tv up one level */ ! 562: struct timer_list *timer; ! 563: ! 564: timer = tv->vec[tv->index]; ! 565: /* ! 566: * We are removing _all_ timers from the list, so we don't have to ! 567: * detach them individually, just clear the list afterwards. ! 568: */ ! 569: while (timer) ! 570: { ! 571: struct timer_list *tmp = timer; ! 572: timer = timer->next; ! 573: internal_add_timer (tmp); ! 574: } ! 575: tv->vec[tv->index] = NULL; ! 576: tv->index = (tv->index + 1) & TVN_MASK; ! 577: } ! 578: ! 579: static inline void ! 580: run_timer_list (void) ! 581: { ! 582: cli (); ! 583: while ((long) (jiffies - timer_jiffies) >= 0) ! 584: { ! 585: struct timer_list *timer; ! 586: ! 587: if (!tv1.index) ! 588: { ! 589: int n = 1; ! 590: ! 591: do ! 592: { ! 593: cascade_timers (tvecs[n]); ! 594: } ! 595: while (tvecs[n]->index == 1 && ++n < NOOF_TVECS); ! 596: } ! 597: while ((timer = tv1.vec[tv1.index])) ! 598: { ! 599: void (*fn) (unsigned long) = timer->function; ! 600: unsigned long data = timer->data; ! 601: ! 602: detach_timer (timer); ! 603: timer->next = timer->prev = NULL; ! 604: sti (); ! 605: fn (data); ! 606: cli (); ! 607: } ! 608: ++timer_jiffies; ! 609: tv1.index = (tv1.index + 1) & TVR_MASK; ! 610: } ! 611: sti (); ! 612: } ! 613: ! 614: /* ! 615: * Timer software interrupt handler. ! 616: */ ! 617: static void ! 618: timer_bh (void) ! 619: { ! 620: run_old_timers (); ! 621: run_timer_list (); ! 622: } ! 623: ! 624: #if 0 ! 625: int linux_timer_print = 0; ! 626: #endif ! 627: ! 628: /* ! 629: * Timer interrupt handler. ! 630: */ ! 631: void ! 632: linux_timer_intr (void) ! 633: { ! 634: (*(unsigned long *) &jiffies)++; ! 635: mark_bh (TIMER_BH); ! 636: if (tq_timer) ! 637: mark_bh (TQUEUE_BH); ! 638: #if 0 ! 639: if (linux_timer_print) ! 640: printf ("linux_timer_intr: pic_mask[0] %x\n", pic_mask[0]); ! 641: #endif ! 642: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.