140 lines · c
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 and13 * parent.14 */15struct 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 60int 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 79void destroy_child_sync(struct child_sync *sync)80{81 sem_destroy(&sync->sem_parent);82 sem_destroy(&sync->sem_child);83}84 85int 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 99int 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 113int 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 127int 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