diff --git a/list.h b/list.h index a226a870dc..eb601192f4 100644 --- a/list.h +++ b/list.h @@ -163,4 +163,42 @@ static inline void list_replace_init(struct list_head *old, INIT_LIST_HEAD(old); } +/* + * This is exactly the same as a normal list_head, except that it can be + * declared volatile (e.g., if you have a list that may be accessed from signal + * handlers). + */ +struct volatile_list_head { + volatile struct volatile_list_head *next, *prev; +}; + +#define VOLATILE_LIST_HEAD(name) \ + volatile struct volatile_list_head name = { &(name), &(name) } + +static inline void __volatile_list_del(volatile struct volatile_list_head *prev, + volatile struct volatile_list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void volatile_list_del(volatile struct volatile_list_head *elem) +{ + __volatile_list_del(elem->prev, elem->next); +} + +static inline int volatile_list_empty(volatile struct volatile_list_head *head) +{ + return head == head->next; +} + +static inline void volatile_list_add(volatile struct volatile_list_head *newp, + volatile struct volatile_list_head *head) +{ + head->next->prev = newp; + newp->next = head->next; + newp->prev = head; + head->next = newp; +} + #endif /* LIST_H */ diff --git a/tempfile.c b/tempfile.c index e655e28477..11bda824cf 100644 --- a/tempfile.c +++ b/tempfile.c @@ -55,14 +55,16 @@ #include "tempfile.h" #include "sigchain.h" -static struct tempfile *volatile tempfile_list; +static VOLATILE_LIST_HEAD(tempfile_list); static void remove_tempfiles(int in_signal_handler) { pid_t me = getpid(); - struct tempfile *volatile p; + volatile struct volatile_list_head *pos; + + list_for_each(pos, &tempfile_list) { + struct tempfile *p = list_entry(pos, struct tempfile, list); - for (p = tempfile_list; p; p = p->next) { if (!is_tempfile_active(p) || p->owner != me) continue; @@ -95,7 +97,7 @@ static void remove_tempfiles_on_signal(int signo) */ static void prepare_tempfile_object(struct tempfile *tempfile) { - if (!tempfile_list) { + if (volatile_list_empty(&tempfile_list)) { /* One-time initialization */ sigchain_push_common(remove_tempfiles_on_signal); atexit(remove_tempfiles_on_exit); @@ -110,8 +112,7 @@ static void prepare_tempfile_object(struct tempfile *tempfile) tempfile->active = 0; tempfile->owner = 0; strbuf_init(&tempfile->filename, 0); - tempfile->next = tempfile_list; - tempfile_list = tempfile; + volatile_list_add(&tempfile->list, &tempfile_list); tempfile->on_list = 1; } else if (tempfile->filename.len) { /* This shouldn't happen, but better safe than sorry. */ diff --git a/tempfile.h b/tempfile.h index d30663182d..2ee24f4380 100644 --- a/tempfile.h +++ b/tempfile.h @@ -1,6 +1,8 @@ #ifndef TEMPFILE_H #define TEMPFILE_H +#include "list.h" + /* * Handle temporary files. * @@ -81,7 +83,7 @@ */ struct tempfile { - struct tempfile *volatile next; + volatile struct volatile_list_head list; volatile sig_atomic_t active; volatile int fd; FILE *volatile fp;