summaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/powerpc/ptrace/child.h
blob: d7275b7b33dc9f6e476270ccdedac039cb4c6f89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// 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;
}