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