1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Helper functions to sync execution between parent and child processes. |
4 | * |
5 | * Copyright 2018, Thiago Jung Bauermann, IBM Corporation. |
6 | */ |
7 | #include <stdio.h> |
8 | #include <stdbool.h> |
9 | #include <semaphore.h> |
10 | |
11 | /* |
12 | * Information in a shared memory location for synchronization between child and |
13 | * parent. |
14 | */ |
15 | struct child_sync { |
16 | /* The parent waits on this semaphore. */ |
17 | sem_t sem_parent; |
18 | |
19 | /* If true, the child should give up as well. */ |
20 | bool parent_gave_up; |
21 | |
22 | /* The child waits on this semaphore. */ |
23 | sem_t sem_child; |
24 | |
25 | /* If true, the parent should give up as well. */ |
26 | bool child_gave_up; |
27 | }; |
28 | |
29 | #define CHILD_FAIL_IF(x, sync) \ |
30 | do { \ |
31 | if (x) { \ |
32 | fprintf(stderr, \ |
33 | "[FAIL] Test FAILED on line %d\n", __LINE__); \ |
34 | (sync)->child_gave_up = true; \ |
35 | prod_parent(sync); \ |
36 | return 1; \ |
37 | } \ |
38 | } while (0) |
39 | |
40 | #define PARENT_FAIL_IF(x, sync) \ |
41 | do { \ |
42 | if (x) { \ |
43 | fprintf(stderr, \ |
44 | "[FAIL] Test FAILED on line %d\n", __LINE__); \ |
45 | (sync)->parent_gave_up = true; \ |
46 | prod_child(sync); \ |
47 | return 1; \ |
48 | } \ |
49 | } while (0) |
50 | |
51 | #define PARENT_SKIP_IF_UNSUPPORTED(x, sync, msg) \ |
52 | do { \ |
53 | if ((x) == -1 && (errno == ENODEV || errno == EINVAL)) { \ |
54 | (sync)->parent_gave_up = true; \ |
55 | prod_child(sync); \ |
56 | SKIP_IF_MSG(1, msg); \ |
57 | } \ |
58 | } while (0) |
59 | |
60 | int init_child_sync(struct child_sync *sync) |
61 | { |
62 | int ret; |
63 | |
64 | ret = sem_init(&sync->sem_parent, 1, 0); |
65 | if (ret) { |
66 | perror("Semaphore initialization failed" ); |
67 | return 1; |
68 | } |
69 | |
70 | ret = sem_init(&sync->sem_child, 1, 0); |
71 | if (ret) { |
72 | perror("Semaphore initialization failed" ); |
73 | return 1; |
74 | } |
75 | |
76 | return 0; |
77 | } |
78 | |
79 | void destroy_child_sync(struct child_sync *sync) |
80 | { |
81 | sem_destroy(&sync->sem_parent); |
82 | sem_destroy(&sync->sem_child); |
83 | } |
84 | |
85 | int wait_child(struct child_sync *sync) |
86 | { |
87 | int ret; |
88 | |
89 | /* Wait until the child prods us. */ |
90 | ret = sem_wait(&sync->sem_parent); |
91 | if (ret) { |
92 | perror("Error waiting for child" ); |
93 | return 1; |
94 | } |
95 | |
96 | return sync->child_gave_up; |
97 | } |
98 | |
99 | int prod_child(struct child_sync *sync) |
100 | { |
101 | int ret; |
102 | |
103 | /* Unblock the child now. */ |
104 | ret = sem_post(&sync->sem_child); |
105 | if (ret) { |
106 | perror("Error prodding child" ); |
107 | return 1; |
108 | } |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | int wait_parent(struct child_sync *sync) |
114 | { |
115 | int ret; |
116 | |
117 | /* Wait until the parent prods us. */ |
118 | ret = sem_wait(&sync->sem_child); |
119 | if (ret) { |
120 | perror("Error waiting for parent" ); |
121 | return 1; |
122 | } |
123 | |
124 | return sync->parent_gave_up; |
125 | } |
126 | |
127 | int prod_parent(struct child_sync *sync) |
128 | { |
129 | int ret; |
130 | |
131 | /* Unblock the parent now. */ |
132 | ret = sem_post(&sync->sem_parent); |
133 | if (ret) { |
134 | perror("Error prodding parent" ); |
135 | return 1; |
136 | } |
137 | |
138 | return 0; |
139 | } |
140 | |