18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Helper functions to sync execution between parent and child processes.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2018, Thiago Jung Bauermann, IBM Corporation.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <stdio.h>
88c2ecf20Sopenharmony_ci#include <stdbool.h>
98c2ecf20Sopenharmony_ci#include <semaphore.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * Information in a shared memory location for synchronization between child and
138c2ecf20Sopenharmony_ci * parent.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_cistruct child_sync {
168c2ecf20Sopenharmony_ci	/* The parent waits on this semaphore. */
178c2ecf20Sopenharmony_ci	sem_t sem_parent;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	/* If true, the child should give up as well. */
208c2ecf20Sopenharmony_ci	bool parent_gave_up;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	/* The child waits on this semaphore. */
238c2ecf20Sopenharmony_ci	sem_t sem_child;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	/* If true, the parent should give up as well. */
268c2ecf20Sopenharmony_ci	bool child_gave_up;
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define CHILD_FAIL_IF(x, sync)						\
308c2ecf20Sopenharmony_ci	do {								\
318c2ecf20Sopenharmony_ci		if (x) {						\
328c2ecf20Sopenharmony_ci			fprintf(stderr,					\
338c2ecf20Sopenharmony_ci				"[FAIL] Test FAILED on line %d\n", __LINE__); \
348c2ecf20Sopenharmony_ci			(sync)->child_gave_up = true;			\
358c2ecf20Sopenharmony_ci			prod_parent(sync);				\
368c2ecf20Sopenharmony_ci			return 1;					\
378c2ecf20Sopenharmony_ci		}							\
388c2ecf20Sopenharmony_ci	} while (0)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define PARENT_FAIL_IF(x, sync)						\
418c2ecf20Sopenharmony_ci	do {								\
428c2ecf20Sopenharmony_ci		if (x) {						\
438c2ecf20Sopenharmony_ci			fprintf(stderr,					\
448c2ecf20Sopenharmony_ci				"[FAIL] Test FAILED on line %d\n", __LINE__); \
458c2ecf20Sopenharmony_ci			(sync)->parent_gave_up = true;			\
468c2ecf20Sopenharmony_ci			prod_child(sync);				\
478c2ecf20Sopenharmony_ci			return 1;					\
488c2ecf20Sopenharmony_ci		}							\
498c2ecf20Sopenharmony_ci	} while (0)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define PARENT_SKIP_IF_UNSUPPORTED(x, sync)				\
528c2ecf20Sopenharmony_ci	do {								\
538c2ecf20Sopenharmony_ci		if ((x) == -1 && (errno == ENODEV || errno == EINVAL)) { \
548c2ecf20Sopenharmony_ci			(sync)->parent_gave_up = true;			\
558c2ecf20Sopenharmony_ci			prod_child(sync);				\
568c2ecf20Sopenharmony_ci			SKIP_IF(1);					\
578c2ecf20Sopenharmony_ci		}							\
588c2ecf20Sopenharmony_ci	} while (0)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ciint init_child_sync(struct child_sync *sync)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	int ret;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	ret = sem_init(&sync->sem_parent, 1, 0);
658c2ecf20Sopenharmony_ci	if (ret) {
668c2ecf20Sopenharmony_ci		perror("Semaphore initialization failed");
678c2ecf20Sopenharmony_ci		return 1;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	ret = sem_init(&sync->sem_child, 1, 0);
718c2ecf20Sopenharmony_ci	if (ret) {
728c2ecf20Sopenharmony_ci		perror("Semaphore initialization failed");
738c2ecf20Sopenharmony_ci		return 1;
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_civoid destroy_child_sync(struct child_sync *sync)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	sem_destroy(&sync->sem_parent);
828c2ecf20Sopenharmony_ci	sem_destroy(&sync->sem_child);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciint wait_child(struct child_sync *sync)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	int ret;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* Wait until the child prods us. */
908c2ecf20Sopenharmony_ci	ret = sem_wait(&sync->sem_parent);
918c2ecf20Sopenharmony_ci	if (ret) {
928c2ecf20Sopenharmony_ci		perror("Error waiting for child");
938c2ecf20Sopenharmony_ci		return 1;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	return sync->child_gave_up;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint prod_child(struct child_sync *sync)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	int ret;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/* Unblock the child now. */
1048c2ecf20Sopenharmony_ci	ret = sem_post(&sync->sem_child);
1058c2ecf20Sopenharmony_ci	if (ret) {
1068c2ecf20Sopenharmony_ci		perror("Error prodding child");
1078c2ecf20Sopenharmony_ci		return 1;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ciint wait_parent(struct child_sync *sync)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	int ret;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* Wait until the parent prods us. */
1188c2ecf20Sopenharmony_ci	ret = sem_wait(&sync->sem_child);
1198c2ecf20Sopenharmony_ci	if (ret) {
1208c2ecf20Sopenharmony_ci		perror("Error waiting for parent");
1218c2ecf20Sopenharmony_ci		return 1;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return sync->parent_gave_up;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ciint prod_parent(struct child_sync *sync)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	int ret;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* Unblock the parent now. */
1328c2ecf20Sopenharmony_ci	ret = sem_post(&sync->sem_parent);
1338c2ecf20Sopenharmony_ci	if (ret) {
1348c2ecf20Sopenharmony_ci		perror("Error prodding parent");
1358c2ecf20Sopenharmony_ci		return 1;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return 0;
1398c2ecf20Sopenharmony_ci}
140