VM: full munmap
[minix.git] / lib / libsys / spin.c
blob3e47c0d96d88c8278436abfe831ed73132ace1b5
1 /* Helper functions that allow driver writers to easily busy-wait (spin) for a
2 * condition to become satisfied within a certain maximum time span.
3 */
4 /* This implementation first spins without making any system calls for a
5 * while, and then starts using system calls (specifically, the system call to
6 * obtain the current time) while spinning. The reason for this is that in
7 * many cases, the condition to be checked will become satisfied rather
8 * quickly, and we want to avoid getting descheduled in that case. However,
9 * after a while, running out of scheduling quantum will cause our priority to
10 * be lowered, and we can avoid this by voluntarily giving up the CPU, by
11 * making a system call.
13 #include "sysutil.h"
14 #include <minix/spin.h>
15 #include <minix/minlib.h>
17 /* Number of microseconds to keep spinning initially, without performing a
18 * system call. We pick a value somewhat smaller than a typical clock tick.
19 * Note that for the above reasons, we want to avoid using sys_hz() here.
21 #define TSC_SPIN 1000 /* in microseconds */
23 /* Internal spin states. */
24 enum {
25 STATE_INIT, /* simply check the condition (once) */
26 STATE_BASE_TS, /* get the initial TSC value (once) */
27 STATE_TS, /* use the TSC to spin (up to TSC_SPIN us) */
28 STATE_UPTIME /* use the clock to spin */
31 void spin_init(spin_t *s, u32_t usecs)
33 /* Initialize the given spin state structure, set to spin at most the
34 * given number of microseconds.
36 s->s_state = STATE_INIT;
37 s->s_usecs = usecs;
38 s->s_timeout = FALSE;
41 int spin_check(spin_t *s)
43 /* Check whether a timeout has taken place. Return TRUE if the caller
44 * should continue spinning, and FALSE if a timeout has occurred. The
45 * implementation assumes that it is okay to spin a little bit too long
46 * (up to a full clock tick extra).
48 u64_t cur_tsc, tsc_delta;
49 clock_t now, micro_delta;
51 switch (s->s_state) {
52 case STATE_INIT:
53 s->s_state = STATE_BASE_TS;
54 break;
56 case STATE_BASE_TS:
57 s->s_state = STATE_TS;
58 read_tsc_64(&s->s_base_tsc);
59 break;
61 case STATE_TS:
62 read_tsc_64(&cur_tsc);
64 tsc_delta = sub64(cur_tsc, s->s_base_tsc);
66 micro_delta = tsc_64_to_micros(tsc_delta);
68 if (micro_delta >= s->s_usecs) {
69 s->s_timeout = TRUE;
70 return FALSE;
73 if (micro_delta >= TSC_SPIN) {
74 s->s_usecs -= micro_delta;
75 getuptime(&s->s_base_uptime);
76 s->s_state = STATE_UPTIME;
79 break;
81 case STATE_UPTIME:
82 getuptime(&now);
84 /* We assume that sys_hz() caches its return value. */
85 micro_delta = ((now - s->s_base_uptime) * 1000 / sys_hz()) *
86 1000;
88 if (micro_delta >= s->s_usecs) {
89 s->s_timeout = TRUE;
90 return FALSE;
93 break;
95 default:
96 panic("spin_check: invalid state %d", s->s_state);
99 return TRUE;