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 } 140