summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--list.h38
-rw-r--r--tempfile.c13
-rw-r--r--tempfile.h4
3 files changed, 48 insertions, 7 deletions
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;