1
/* Copyright (c) 2016-2018, Linaro Limited
2
 * All rights reserved.
3
 *
4
 * SPDX-License-Identifier:     BSD-3-Clause
5
 */
6

7
#ifndef _GNU_SOURCE
8
#define _GNU_SOURCE
9
#endif
10
#include <sched.h>
11
#include <unistd.h>
12
#include <sys/types.h>
13
#include <sys/wait.h>
14
#include <sys/prctl.h>
15
#include <sys/syscall.h>
16

17
#include <stdlib.h>
18
#include <string.h>
19
#include <stdio.h>
20
#include <stdbool.h>
21

22
#include <odp_api.h>
23
#include <odp/helper/linux/pthread.h>
24
#include <odp/helper/linux/process.h>
25
#include <odp/helper/odph_debug.h>
26

27 1
static void *_odph_run_start_routine(void *arg)
28
{
29 1
	odph_linux_thr_params_t *thr_params = arg;
30

31
	/* ODP thread local init */
32 1
	if (odp_init_local(thr_params->instance, thr_params->thr_type)) {
33 0
		ODPH_ERR("Local init failed\n");
34 0
		return NULL;
35
	}
36

37 1
	void *ret_ptr = thr_params->start(thr_params->arg);
38 1
	int ret = odp_term_local();
39

40 1
	if (ret < 0)
41 1
		ODPH_ERR("Local term failed\n");
42

43 1
	return ret_ptr;
44
}
45

46 1
int odph_linux_pthread_create(odph_linux_pthread_t *pthread_tbl,
47
			      const odp_cpumask_t *mask,
48
			      const odph_linux_thr_params_t *thr_params)
49
{
50
	int i;
51
	int num;
52
	int cpu_count;
53
	int cpu;
54
	int ret;
55

56 1
	num = odp_cpumask_count(mask);
57

58 1
	memset(pthread_tbl, 0, num * sizeof(odph_linux_pthread_t));
59

60 1
	cpu_count = odp_cpu_count();
61

62 1
	if (num < 1 || num > cpu_count) {
63 0
		ODPH_ERR("Invalid number of threads:%d (%d cores available)\n",
64
			 num, cpu_count);
65 0
		return 0;
66
	}
67

68 1
	cpu = odp_cpumask_first(mask);
69 1
	for (i = 0; i < num; i++) {
70
		cpu_set_t cpu_set;
71

72 1
		CPU_ZERO(&cpu_set);
73 1
		CPU_SET(cpu, &cpu_set);
74

75 1
		pthread_attr_init(&pthread_tbl[i].attr);
76

77 1
		pthread_tbl[i].cpu = cpu;
78

79 1
		pthread_attr_setaffinity_np(&pthread_tbl[i].attr,
80
					    sizeof(cpu_set_t), &cpu_set);
81

82 1
		pthread_tbl[i].thr_params.start    = thr_params->start;
83 1
		pthread_tbl[i].thr_params.arg      = thr_params->arg;
84 1
		pthread_tbl[i].thr_params.thr_type = thr_params->thr_type;
85 1
		pthread_tbl[i].thr_params.instance = thr_params->instance;
86

87 1
		ret = pthread_create(&pthread_tbl[i].thread,
88 1
				     &pthread_tbl[i].attr,
89
				     _odph_run_start_routine,
90 1
				     &pthread_tbl[i].thr_params);
91 1
		if (ret != 0) {
92 0
			ODPH_ERR("Failed to start thread on CPU #%d: %d\n", cpu,
93
				 ret);
94 0
			break;
95
		}
96

97 1
		cpu = odp_cpumask_next(mask, cpu);
98
	}
99

100 1
	return i;
101
}
102

103 1
void odph_linux_pthread_join(odph_linux_pthread_t *thread_tbl, int num)
104
{
105
	int i;
106
	int ret;
107

108 1
	for (i = 0; i < num; i++) {
109
		/* Wait thread to exit */
110 1
		ret = pthread_join(thread_tbl[i].thread, NULL);
111 1
		if (ret != 0) {
112 1
			ODPH_ERR("Failed to join thread from cpu #%d\n",
113
				 thread_tbl[i].cpu);
114
		}
115 1
		pthread_attr_destroy(&thread_tbl[i].attr);
116
	}
117
}
118

119 1
int odph_linux_process_fork_n(odph_linux_process_t *proc_tbl,
120
			      const odp_cpumask_t *mask,
121
			      const odph_linux_thr_params_t *thr_params)
122
{
123
	pid_t pid;
124
	int num;
125
	int cpu_count;
126
	int cpu;
127
	int i;
128

129 1
	num = odp_cpumask_count(mask);
130

131 1
	memset(proc_tbl, 0, num * sizeof(odph_linux_process_t));
132

133 1
	cpu_count = odp_cpu_count();
134

135 1
	if (num < 1 || num > cpu_count) {
136 0
		ODPH_ERR("Bad num\n");
137 0
		return -1;
138
	}
139

140 1
	cpu = odp_cpumask_first(mask);
141 1
	for (i = 0; i < num; i++) {
142
		cpu_set_t cpu_set;
143

144 1
		CPU_ZERO(&cpu_set);
145 1
		CPU_SET(cpu, &cpu_set);
146

147 1
		pid = fork();
148

149 1
		if (pid < 0) {
150 0
			ODPH_ERR("fork() failed\n");
151 1
			return -1;
152
		}
153

154
		/* Parent continues to fork */
155 1
		if (pid > 0) {
156 1
			proc_tbl[i].pid  = pid;
157 1
			proc_tbl[i].cpu = cpu;
158

159 1
			cpu = odp_cpumask_next(mask, cpu);
160 1
			continue;
161
		}
162

163
		/* Child process */
164

165
		/* Request SIGTERM if parent dies */
166 1
		prctl(PR_SET_PDEATHSIG, SIGTERM);
167
		/* Parent died already? */
168 1
		if (getppid() == 1)
169 0
			kill(getpid(), SIGTERM);
170

171 1
		if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set)) {
172 0
			ODPH_ERR("sched_setaffinity() failed\n");
173 0
			return -2;
174
		}
175

176 1
		if (odp_init_local(thr_params->instance,
177
				   thr_params->thr_type)) {
178 0
			ODPH_ERR("Local init failed\n");
179 0
			return -2;
180
		}
181

182 1
		return 0;
183
	}
184

185 1
	return 1;
186
}
187

188 0
int odph_linux_process_fork(odph_linux_process_t *proc, int cpu,
189
			    const odph_linux_thr_params_t *thr_params)
190
{
191
	odp_cpumask_t mask;
192

193 0
	odp_cpumask_zero(&mask);
194 0
	odp_cpumask_set(&mask, cpu);
195 0
	return odph_linux_process_fork_n(proc, &mask, thr_params);
196
}
197

198 1
int odph_linux_process_wait_n(odph_linux_process_t *proc_tbl, int num)
199
{
200
	pid_t pid;
201
	int i, j;
202 1
	int status = 0;
203

204 1
	for (i = 0; i < num; i++) {
205 1
		pid = wait(&status);
206

207 1
		if (pid < 0) {
208 0
			ODPH_ERR("wait() failed\n");
209 0
			return -1;
210
		}
211

212 1
		for (j = 0; j < num; j++) {
213 1
			if (proc_tbl[j].pid == pid) {
214 1
				proc_tbl[j].status = status;
215 1
				break;
216
			}
217
		}
218

219 1
		if (j == num) {
220 0
			ODPH_ERR("Bad pid:%d\n", (int)pid);
221 0
			return -1;
222
		}
223

224
		/* Examine the child process' termination status */
225 1
		if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) {
226 0
			ODPH_ERR("Child exit status:%d (pid:%d)\n",
227
				 WEXITSTATUS(status), (int)pid);
228 0
			return -1;
229
		}
230 1
		if (WIFSIGNALED(status)) {
231 0
			int signo = WTERMSIG(status);
232

233 0
			ODPH_ERR("Child term signo:%d - %s (pid:%d)\n",
234
				 signo, strsignal(signo), (int)pid);
235 0
			return -1;
236
		}
237
	}
238

239 1
	return 0;
240
}

Read our documentation on viewing source code .

Loading