summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/process.h11
-rw-r--r--src/process.c16
-rw-r--r--src/run.c3
-rw-r--r--src/sync-mode.c14
4 files changed, 34 insertions, 10 deletions
diff --git a/include/process.h b/include/process.h
index a7f07ea..9d29f22 100644
--- a/include/process.h
+++ b/include/process.h
@@ -1,14 +1,23 @@
#ifndef _PROCESS_H_
#define _PROCESS_H_
+enum process_type {
+ CTD_PROC_ANY, /* any type */
+ CTD_PROC_FLUSH, /* flush process */
+ CTD_PROC_COMMIT, /* commit process */
+};
+
+#define CTD_PROC_F_EXCL (1 << 0) /* only one process at a time */
+
struct child_process {
struct list_head head;
int pid;
+ int type;
void (*cb)(void *data);
void *data;
};
-int fork_process_new(void (*cb)(void *data), void *data);
+int fork_process_new(int type, int flags, void (*cb)(void *data), void *data);
int fork_process_delete(int pid);
#endif
diff --git a/src/process.c b/src/process.c
index 31e6e6f..c378f7a 100644
--- a/src/process.c
+++ b/src/process.c
@@ -22,20 +22,32 @@
static LIST_HEAD(process_list);
-int fork_process_new(void (*cb)(void *data), void *data)
+int fork_process_new(int type, int flags, void (*cb)(void *data), void *data)
{
- struct child_process *c;
+ struct child_process *c, *this;
int pid;
/* block SIGCHLD to avoid the access of the list concurrently */
sigprocmask(SIG_BLOCK, &STATE(block), NULL);
+ /* We only want one process of this type at the same time. This is
+ * useful if you want to prevent two child processes from accessing
+ * a shared descriptor at the same time. */
+ if (flags & CTD_PROC_F_EXCL) {
+ list_for_each_entry(this, &process_list, head) {
+ if (this->type == type) {
+ sigprocmask(SIG_UNBLOCK, &STATE(block), NULL);
+ return -1;
+ }
+ }
+ }
c = calloc(sizeof(struct child_process), 1);
if (c == NULL) {
sigprocmask(SIG_UNBLOCK, &STATE(block), NULL);
return -1;
}
+ c->type = type;
c->cb = cb;
c->data = data;
c->pid = pid = fork();
diff --git a/src/run.c b/src/run.c
index 21ff715..a0aea4f 100644
--- a/src/run.c
+++ b/src/run.c
@@ -218,7 +218,8 @@ void local_handler(int fd, void *data)
/* fork a child process that performs the flush operation,
* meanwhile the parent process handles events. */
- if (fork_process_new(flush_done_cb, h) == 0) {
+ if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL,
+ flush_done_cb, h) == 0) {
nl_flush_conntrack_table(h);
exit(EXIT_SUCCESS);
}
diff --git a/src/sync-mode.c b/src/sync-mode.c
index 699a585..2da3604 100644
--- a/src/sync-mode.c
+++ b/src/sync-mode.c
@@ -229,7 +229,8 @@ static void do_reset_cache_alarm(struct alarm_block *a, void *data)
/* fork a child process that performs the flush operation,
* meanwhile the parent process handles events. */
- if (fork_process_new(flush_done_cb, h) == 0) {
+ if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL,
+ flush_done_cb, h) == 0) {
nl_flush_conntrack_table(h);
exit(EXIT_SUCCESS);
}
@@ -423,28 +424,28 @@ static int local_handler_sync(int fd, int type, void *data)
switch(type) {
case DUMP_INTERNAL:
- ret = fork_process_new(NULL, NULL);
+ ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL);
if (ret == 0) {
cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN);
exit(EXIT_SUCCESS);
}
break;
case DUMP_EXTERNAL:
- ret = fork_process_new(NULL, NULL);
+ ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL);
if (ret == 0) {
cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN);
exit(EXIT_SUCCESS);
}
break;
case DUMP_INT_XML:
- ret = fork_process_new(NULL, NULL);
+ ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL);
if (ret == 0) {
cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML);
exit(EXIT_SUCCESS);
}
break;
case DUMP_EXT_XML:
- ret = fork_process_new(NULL, NULL);
+ ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL);
if (ret == 0) {
cache_dump(STATE_SYNC(external), fd, NFCT_O_XML);
exit(EXIT_SUCCESS);
@@ -465,7 +466,8 @@ static int local_handler_sync(int fd, int type, void *data)
origin_register(h, CTD_ORIGIN_COMMIT);
/* fork new process and insert it the process list */
- ret = fork_process_new(commit_done_cb, h);
+ ret = fork_process_new(CTD_PROC_COMMIT, CTD_PROC_F_EXCL,
+ commit_done_cb, h);
if (ret == 0) {
dlog(LOG_NOTICE, "committing external cache");
cache_commit(STATE_SYNC(external), h);