162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Helper functions to sync execution between parent and child processes.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2018, Thiago Jung Bauermann, IBM Corporation.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <stdio.h>
862306a36Sopenharmony_ci#include <stdbool.h>
962306a36Sopenharmony_ci#include <semaphore.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * Information in a shared memory location for synchronization between child and
1362306a36Sopenharmony_ci * parent.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_cistruct child_sync {
1662306a36Sopenharmony_ci	/* The parent waits on this semaphore. */
1762306a36Sopenharmony_ci	sem_t sem_parent;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	/* If true, the child should give up as well. */
2062306a36Sopenharmony_ci	bool parent_gave_up;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	/* The child waits on this semaphore. */
2362306a36Sopenharmony_ci	sem_t sem_child;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	/* If true, the parent should give up as well. */
2662306a36Sopenharmony_ci	bool child_gave_up;
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define CHILD_FAIL_IF(x, sync)						\
3062306a36Sopenharmony_ci	do {								\
3162306a36Sopenharmony_ci		if (x) {						\
3262306a36Sopenharmony_ci			fprintf(stderr,					\
3362306a36Sopenharmony_ci				"[FAIL] Test FAILED on line %d\n", __LINE__); \
3462306a36Sopenharmony_ci			(sync)->child_gave_up = true;			\
3562306a36Sopenharmony_ci			prod_parent(sync);				\
3662306a36Sopenharmony_ci			return 1;					\
3762306a36Sopenharmony_ci		}							\
3862306a36Sopenharmony_ci	} while (0)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define PARENT_FAIL_IF(x, sync)						\
4162306a36Sopenharmony_ci	do {								\
4262306a36Sopenharmony_ci		if (x) {						\
4362306a36Sopenharmony_ci			fprintf(stderr,					\
4462306a36Sopenharmony_ci				"[FAIL] Test FAILED on line %d\n", __LINE__); \
4562306a36Sopenharmony_ci			(sync)->parent_gave_up = true;			\
4662306a36Sopenharmony_ci			prod_child(sync);				\
4762306a36Sopenharmony_ci			return 1;					\
4862306a36Sopenharmony_ci		}							\
4962306a36Sopenharmony_ci	} while (0)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define PARENT_SKIP_IF_UNSUPPORTED(x, sync, msg)			\
5262306a36Sopenharmony_ci	do {								\
5362306a36Sopenharmony_ci		if ((x) == -1 && (errno == ENODEV || errno == EINVAL)) { \
5462306a36Sopenharmony_ci			(sync)->parent_gave_up = true;			\
5562306a36Sopenharmony_ci			prod_child(sync);				\
5662306a36Sopenharmony_ci			SKIP_IF_MSG(1, msg);				\
5762306a36Sopenharmony_ci		}							\
5862306a36Sopenharmony_ci	} while (0)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciint init_child_sync(struct child_sync *sync)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	int ret;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	ret = sem_init(&sync->sem_parent, 1, 0);
6562306a36Sopenharmony_ci	if (ret) {
6662306a36Sopenharmony_ci		perror("Semaphore initialization failed");
6762306a36Sopenharmony_ci		return 1;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	ret = sem_init(&sync->sem_child, 1, 0);
7162306a36Sopenharmony_ci	if (ret) {
7262306a36Sopenharmony_ci		perror("Semaphore initialization failed");
7362306a36Sopenharmony_ci		return 1;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	return 0;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_civoid destroy_child_sync(struct child_sync *sync)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	sem_destroy(&sync->sem_parent);
8262306a36Sopenharmony_ci	sem_destroy(&sync->sem_child);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciint wait_child(struct child_sync *sync)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	int ret;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Wait until the child prods us. */
9062306a36Sopenharmony_ci	ret = sem_wait(&sync->sem_parent);
9162306a36Sopenharmony_ci	if (ret) {
9262306a36Sopenharmony_ci		perror("Error waiting for child");
9362306a36Sopenharmony_ci		return 1;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return sync->child_gave_up;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciint prod_child(struct child_sync *sync)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	int ret;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* Unblock the child now. */
10462306a36Sopenharmony_ci	ret = sem_post(&sync->sem_child);
10562306a36Sopenharmony_ci	if (ret) {
10662306a36Sopenharmony_ci		perror("Error prodding child");
10762306a36Sopenharmony_ci		return 1;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return 0;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciint wait_parent(struct child_sync *sync)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	int ret;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* Wait until the parent prods us. */
11862306a36Sopenharmony_ci	ret = sem_wait(&sync->sem_child);
11962306a36Sopenharmony_ci	if (ret) {
12062306a36Sopenharmony_ci		perror("Error waiting for parent");
12162306a36Sopenharmony_ci		return 1;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return sync->parent_gave_up;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ciint prod_parent(struct child_sync *sync)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	int ret;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* Unblock the parent now. */
13262306a36Sopenharmony_ci	ret = sem_post(&sync->sem_parent);
13362306a36Sopenharmony_ci	if (ret) {
13462306a36Sopenharmony_ci		perror("Error prodding parent");
13562306a36Sopenharmony_ci		return 1;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
140