Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/sched/sleep.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "arch/i386.h"
0019 #include "arch/i386-div64.h"
0020 #include "kernel.h"
0021 #include "smp/smp.h"
0022 #include "smp/apic.h"
0023 #include "util/printf.h"
0024 #include "sched/sched.h"
0025 
0026 /* Scheduler-integrated blocking sleep routines */
0027 
0028 //#define DEBUG_SCHED_SLEEP
0029 
0030 #ifdef DEBUG_SCHED_SLEEP
0031 #define DLOG(fmt,...) DLOG_PREFIX("sched-sleep",fmt,##__VA_ARGS__)
0032 #else
0033 #define DLOG(fmt,...) ;
0034 #endif
0035 
0036 static task_id sleepqueue = 0;
0037 
0038 extern uint64 tsc_freq;         /* timestamp counter frequency */
0039 
0040 static inline uint64
0041 compute_finish (uint32 usec)
0042 {
0043   uint64 ticks;
0044   uint64 start;
0045 
0046   RDTSC (start);
0047 
0048   ticks = div64_64 (tsc_freq * (u64) usec, 1000000LL);
0049 
0050   return start + ticks;
0051 }
0052 
0053 /* Must hold lock */
0054 extern void
0055 sched_usleep (uint32 usec)
0056 {
0057   if (mp_enabled) {
0058     task_id sel;
0059     quest_tss *tssp;
0060     uint64 finish = compute_finish (usec);
0061 #ifdef DEBUG_SCHED_SLEEP
0062     u64 now; RDTSC (now);
0063 #endif
0064     sel = str ();
0065     DLOG ("task 0x%x sleeping for %d usec (0x%llX -> 0x%llX)",
0066           sel, usec, now, finish);
0067     tssp = lookup_TSS (sel);
0068     tssp->time = finish;
0069     queue_append (&sleepqueue, sel);
0070 
0071     schedule ();
0072   } else
0073     /* interrupts not enabled */
0074     tsc_delay_usec (usec);
0075 }
0076 
0077 /* Spin for a given amount of microsec. */
0078 extern void
0079 tsc_delay_usec (uint32 usec)
0080 {
0081   uint64 value, finish;
0082 
0083   finish = compute_finish (usec);
0084   for (;;) {
0085     RDTSC (value);
0086     if (value >= finish)
0087       break;
0088     asm volatile ("pause");
0089   }
0090 }
0091 
0092 /* Must hold lock */
0093 extern void
0094 process_sleepqueue (void)
0095 {
0096   uint64 now;
0097   task_id *q, next;
0098   quest_tss *tssp;
0099 
0100   RDTSC (now);
0101 
0102   if (sleepqueue == 0)
0103     return;
0104 
0105   q = &sleepqueue;
0106   tssp = lookup_TSS (sleepqueue);
0107   DLOG ("process_sleepqueue 0x%llX", now);
0108   for (;;) {
0109     /* examine finish time of task */
0110     next = tssp->next;
0111 
0112     if (tssp->time <= now) {
0113       DLOG ("waking task 0x%x (0x%llX <= 0x%llX)", *q, tssp->time, now);
0114       /* time to wake-up */
0115       wakeup (*q);
0116       /* remove from sleepqueue */
0117       *q = next;
0118       tssp->time = 0;
0119     } else
0120       q = &tssp->next;
0121 
0122     /* move to next sleeper */
0123     if (next == 0)
0124       break;
0125     tssp = lookup_TSS (*q);
0126   }
0127 }
0128 
0129 /*
0130  * Local Variables:
0131  * indent-tabs-mode: nil
0132  * mode: C
0133  * c-file-style: "gnu"
0134  * c-basic-offset: 2
0135  * End:
0136  */
0137 
0138 /* vi: set et sw=2 sts=2: */