#include #include #include #include #include #include #define REQUEST SIGRTMIN #define GRANT SIGRTMIN+1 #define DONE SIGRTMIN+2 typedef struct queue_t { struct queue_t * next, *prev; pid_t pid; }queue_t; sigset_t oldset; void blocksigs () { sigset_t addset; sigemptyset (&addset); sigaddset (&addset, REQUEST); sigaddset (&addset, DONE); sigprocmask (SIG_BLOCK, &addset, &oldset); } void unblocksigs () { sigprocmask (SIG_SETMASK, &oldset, NULL); } queue_t * head = NULL; /* Called from the signal handler with blocked signals */ void enqueue (pid_t pid) { queue_t * newp; if (pid <= 0) return; newp = malloc (sizeof (queue_t)); if (!newp) return; newp->pid = pid; if (head) { newp->next = head; newp->prev = head->prev; newp->next->prev = newp; newp->prev->next = newp; } else { newp->next = newp->prev = newp; head = newp; } } /* Called with unblocked signals */ pid_t dequeue () { pid_t ret = 0; queue_t * tmp; blocksigs (); if (head) { tmp = head; ret = tmp->pid; if (tmp->next == tmp) { head = NULL; } else { tmp->next->prev = tmp->prev; tmp->prev->next = tmp->next; head = tmp->next; } free (tmp); } unblocksigs (); return ret; } volatile pid_t owner = 0; void request_handler (int sig, siginfo_t * info, void * unused) { if ((info->si_code != SI_NOINFO) && (info->si_code <= 0)) { if (info->si_pid > 0) enqueue (info->si_pid); } } void done_handler (int sig, siginfo_t * info, void * unused) { if ((info->si_code != SI_NOINFO) && (info->si_code <= 0)) { if (info->si_pid == owner) owner = 0; } } int main () { pid_t pid; struct sigaction act; sigemptyset (&act.sa_mask); sigaddset (&act.sa_mask, REQUEST); sigaddset (&act.sa_mask, DONE); act.sa_flags = SA_SIGINFO; act.sa_sigaction = request_handler; if (sigaction (REQUEST, &act, NULL) < 0) { perror ("sigaction"); return 1; } act.sa_sigaction = done_handler; if (sigaction (DONE, &act, NULL) < 0) { perror ("sigaction"); return 1; } while (1) { assert (owner == 0); while (1) { pid = dequeue (); if (pid) break; sleep (100); } owner = pid; if (kill (pid, GRANT) < 0) { perror ("kill"); printf ("Can't send GRANT signal to %d\n", (int)pid); owner = 0; continue; } while (owner > 0) { sleep (100); } } return 0; }