Avoid race condition between nap()'s timeout expiring and incoming work calling resume().
This commit is contained in:
parent
e7fb92e33a
commit
d9d4b02002
|
@ -84,9 +84,13 @@ void suspend(void) {
|
|||
schedule();
|
||||
}
|
||||
|
||||
void resume(Process *p) {
|
||||
assert(p->state == PROCESS_WAITING);
|
||||
enqueue_runlist(p);
|
||||
int resume(Process *p) {
|
||||
if (p->state == PROCESS_WAITING) {
|
||||
enqueue_runlist(p);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void driver(void (*f)(void *), void *arg) {
|
||||
|
|
|
@ -40,7 +40,7 @@ extern Process *spawn(process_main_t f, void *arg);
|
|||
extern int nap(long millis); /* 1 for timeout expired; 0 for resumed early */
|
||||
|
||||
extern void suspend(void);
|
||||
extern void resume(Process *p);
|
||||
extern int resume(Process *p);
|
||||
|
||||
extern IOHandle *new_iohandle(int fd);
|
||||
extern void delete_iohandle(IOHandle *h);
|
||||
|
|
|
@ -158,12 +158,32 @@ static void shoveller(void *qv) {
|
|||
}
|
||||
|
||||
static void throck_shovel(queue_extension_t *q) {
|
||||
//int counter = 0;
|
||||
retry:
|
||||
//printf("throck %d %d %p\n", counter++, q->shovel_awake, q->shovel);
|
||||
if (!q->shovel_awake) {
|
||||
q->shovel_awake = 1;
|
||||
if (!q->shovel) {
|
||||
q->shovel_awake = 1;
|
||||
q->shovel = spawn(shoveller, q);
|
||||
} else {
|
||||
resume(q->shovel);
|
||||
if (resume(q->shovel) == -1) {
|
||||
/* The nap() in the shoveller returned and scheduled the
|
||||
shoveller *just* before we got to it, but the shoveller
|
||||
hasn't had a chance to run yet, so hasn't been able to
|
||||
clear q->shovel and exit. The resume() attempt failed
|
||||
because q->shovel's state is PROCESS_RUNNING, now that it
|
||||
has been scheduled by the return of nap(), so we know that
|
||||
we should back off and try again from the top. */
|
||||
yield();
|
||||
goto retry;
|
||||
} else {
|
||||
/* The resume() was successful, i.e. the nap() hadn't returned
|
||||
before we tried to resume(). We know that nap() will return
|
||||
zero (since the timeout didn't fire before the process was
|
||||
resumed), and so the existing shoveller will continue
|
||||
running. */
|
||||
q->shovel_awake = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue