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