GNU Linux-libre 4.19.264-gnu1
[releases.git] / tools / testing / selftests / powerpc / ptrace / child.h
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)                             \
52         do {                                                            \
53                 if ((x) == -1 && (errno == ENODEV || errno == EINVAL)) { \
54                         (sync)->parent_gave_up = true;                  \
55                         prod_child(sync);                               \
56                         SKIP_IF(1);                                     \
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 }