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