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.
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.
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. */
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
;
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
;
53 s
->s_state
= STATE_BASE_TS
;
57 s
->s_state
= STATE_TS
;
58 read_tsc_64(&s
->s_base_tsc
);
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
) {
73 if (micro_delta
>= TSC_SPIN
) {
74 s
->s_usecs
-= micro_delta
;
75 getuptime(&s
->s_base_uptime
);
76 s
->s_state
= STATE_UPTIME
;
84 /* We assume that sys_hz() caches its return value. */
85 micro_delta
= ((now
- s
->s_base_uptime
) * 1000 / sys_hz()) *
88 if (micro_delta
>= s
->s_usecs
) {
96 panic("spin_check: invalid state %d", s
->s_state
);