140 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// 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)				\
 | 
						|
	do {								\
 | 
						|
		if ((x) == -1 && (errno == ENODEV || errno == EINVAL)) { \
 | 
						|
			(sync)->parent_gave_up = true;			\
 | 
						|
			prod_child(sync);				\
 | 
						|
			SKIP_IF(1);					\
 | 
						|
		}							\
 | 
						|
	} 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;
 | 
						|
}
 |