The Pedigree Project 0.1
waits.c
1#define _GNU_SOURCE
2#include <pthread.h>
3#include <signal.h>
4#include <string.h>
5#include <unistd.h>
6
7#include "contract.h"
8
9struct reader {
10 int fd;
11 size_t size;
12 volatile int started, done, handled;
13 ssize_t result;
14 int error;
15 unsigned char bytes[256];
16};
17static struct reader* active_reader;
18static void handler(int signal) {
19 (void)signal;
20 if (active_reader)
21 __atomic_add_fetch(&active_reader->handled, 1, __ATOMIC_RELEASE);
22}
23static void* read_thread(void* argument) {
24 struct reader* reader = argument;
25 __atomic_store_n(&reader->started, 1, __ATOMIC_RELEASE);
26 errno = 0;
27 reader->result = read(reader->fd, reader->bytes, reader->size);
28 reader->error = errno;
29 __atomic_store_n(&reader->done, 1, __ATOMIC_RELEASE);
30 return NULL;
31}
32
33static int interrupted(int restart) {
34 int failed = 0, group = -1, running = 0, installed = 0;
35 pthread_t thread;
36 struct reader reader = {0};
37 struct sigaction old, action = {.sa_handler = handler, .sa_flags = restart ? SA_RESTART : 0};
38 struct fh_file file = {.fd = -1};
39 struct fh_record record;
40 CHECK(!fh_create(&file));
41 group = fh_group(0);
42 CHECK(group >= 0 && !fh_mark(group, &file, FAN_MARK_ADD, FAN_MODIFY));
43 reader.fd = group;
44 reader.size = fh_record_size(&file.handle);
45 sigemptyset(&action.sa_mask);
46 CHECK(!sigaction(SIGUSR1, &action, &old));
47 installed = 1;
48 active_reader = &reader;
49 CHECK(!pthread_create(&thread, NULL, read_thread, &reader));
50 running = 1;
51 CHECK(!fh_wait(&reader.started, 2000));
52 int64_t deadline = fh_now() + 5000000000;
53 while (!__atomic_load_n(&reader.done, __ATOMIC_ACQUIRE) && fh_now() < deadline) {
54 CHECK(!pthread_kill(thread, SIGUSR1));
55 if (restart && __atomic_load_n(&reader.handled, __ATOMIC_ACQUIRE) >= 3)
56 break;
57 fh_pause(2);
58 }
59 CHECK(__atomic_load_n(&reader.handled, __ATOMIC_ACQUIRE) > 0);
60 if (restart) {
61 CHECK(!__atomic_load_n(&reader.done, __ATOMIC_ACQUIRE));
62 CHECK(!fh_modify(&file));
63 CHECK(!fh_wait(&reader.done, 5000));
64 CHECK(reader.result == (ssize_t)reader.size &&
65 !fh_parse(reader.bytes, (size_t)reader.result, &record));
66 CHECK(record.mask == FAN_MODIFY && record.pid == getpid() &&
67 fh_equal(&record.handle, &file.handle));
68 } else {
69 CHECK(!fh_wait(&reader.done, 100));
70 CHECK(reader.result == -1 && reader.error == EINTR);
71 CHECK(!fh_modify(&file));
72 CHECK(!fh_event(group, &file, FAN_MODIFY, getpid()));
73 }
74 CHECK(!pthread_join(thread, NULL));
75 running = 0;
76out:
77 if (group >= 0)
78 close(group);
79 if (running) {
80 if (fh_wait(&reader.done, 5000)) {
81 fprintf(stderr, "FANOTIFY-HANDLE-CONTRACT: reader did not retire result=%ld errno=%d\n",
82 (long)reader.result, reader.error);
83 _exit(90);
84 }
85 pthread_join(thread, NULL);
86 }
87 active_reader = NULL;
88 if (installed)
89 sigaction(SIGUSR1, &old, NULL);
90 fh_close(&file);
91 return failed;
92}
93
94static int last_close(void) {
95 int failed = 0, group = -1, running = 0;
96 pthread_t thread;
97 struct reader reader = {0};
98 struct fh_file file = {.fd = -1};
99 CHECK(!fh_create(&file));
100 group = fh_group(0);
101 CHECK(group >= 0);
102 reader.fd = group;
103 reader.size = fh_record_size(&file.handle);
104 CHECK(!pthread_create(&thread, NULL, read_thread, &reader));
105 running = 1;
106 CHECK(!fh_wait(&reader.started, 2000));
107 CHECK(!close(group));
108 group = -1;
109 CHECK(!fh_wait(&reader.done, 5000));
110 CHECK(reader.result == -1 && reader.error == EBADF);
111 CHECK(!pthread_join(thread, NULL));
112 running = 0;
113out:
114 if (group >= 0)
115 close(group);
116 if (running) {
117 if (fh_wait(&reader.done, 5000))
118 _exit(91);
119 pthread_join(thread, NULL);
120 }
121 fh_close(&file);
122 return failed;
123}
124int fh_waits(void) {
125 return interrupted(0) || interrupted(1) || last_close();
126}
Definition waits.c:9