Home | History | Annotate | Download | only in ptrace
      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