aboutsummaryrefslogtreecommitdiff
path: root/helper/linux
diff options
context:
space:
mode:
authorPetri Savolainen <petri.savolainen@linaro.org>2017-02-03 13:23:59 +0200
committerMaxim Uvarov <maxim.uvarov@linaro.org>2017-02-16 23:30:27 +0300
commitaf5205809e3921ea0c4db5771ea1da5d2f0eaaf5 (patch)
tree792e274bcd065b57a31c67ce455f16c96640ee4d /helper/linux
parent32b94edb4961a3ac1a2e5c90f65ee3f118852151 (diff)
helper: linux: renamed threads_extn to linux helpers
There's no platform specific helpers. Helpers may depend on Linux and make it easier to do common series of Linux system calls. These kind of helpers are grouped into helper/linux directory. Use --enable-helper-linux configuration option to enable support for Linux helpers. Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org> Reviewed-by: Mike Holmes <mike.holmes@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'helper/linux')
-rw-r--r--helper/linux/thread.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/helper/linux/thread.c b/helper/linux/thread.c
new file mode 100644
index 000000000..52d4efc5e
--- /dev/null
+++ b/helper/linux/thread.c
@@ -0,0 +1,239 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <sched.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#include <odp_api.h>
+#include <odp/helper/linux/pthread.h>
+#include <odp/helper/linux/process.h>
+#include "odph_debug.h"
+
+static void *_odph_run_start_routine(void *arg)
+{
+ odph_linux_thr_params_t *thr_params = arg;
+
+ /* ODP thread local init */
+ if (odp_init_local(thr_params->instance, thr_params->thr_type)) {
+ ODPH_ERR("Local init failed\n");
+ return NULL;
+ }
+
+ void *ret_ptr = thr_params->start(thr_params->arg);
+ int ret = odp_term_local();
+
+ if (ret < 0)
+ ODPH_ERR("Local term failed\n");
+
+ return ret_ptr;
+}
+
+int odph_linux_pthread_create(odph_linux_pthread_t *pthread_tbl,
+ const odp_cpumask_t *mask,
+ const odph_linux_thr_params_t *thr_params)
+{
+ int i;
+ int num;
+ int cpu_count;
+ int cpu;
+ int ret;
+
+ num = odp_cpumask_count(mask);
+
+ memset(pthread_tbl, 0, num * sizeof(odph_linux_pthread_t));
+
+ cpu_count = odp_cpu_count();
+
+ if (num < 1 || num > cpu_count) {
+ ODPH_ERR("Invalid number of threads:%d (%d cores available)\n",
+ num, cpu_count);
+ return 0;
+ }
+
+ cpu = odp_cpumask_first(mask);
+ for (i = 0; i < num; i++) {
+ cpu_set_t cpu_set;
+
+ CPU_ZERO(&cpu_set);
+ CPU_SET(cpu, &cpu_set);
+
+ pthread_attr_init(&pthread_tbl[i].attr);
+
+ pthread_tbl[i].cpu = cpu;
+
+ pthread_attr_setaffinity_np(&pthread_tbl[i].attr,
+ sizeof(cpu_set_t), &cpu_set);
+
+ pthread_tbl[i].thr_params.start = thr_params->start;
+ pthread_tbl[i].thr_params.arg = thr_params->arg;
+ pthread_tbl[i].thr_params.thr_type = thr_params->thr_type;
+ pthread_tbl[i].thr_params.instance = thr_params->instance;
+
+ ret = pthread_create(&pthread_tbl[i].thread,
+ &pthread_tbl[i].attr,
+ _odph_run_start_routine,
+ &pthread_tbl[i].thr_params);
+ if (ret != 0) {
+ ODPH_ERR("Failed to start thread on cpu #%d\n", cpu);
+ break;
+ }
+
+ cpu = odp_cpumask_next(mask, cpu);
+ }
+
+ return i;
+}
+
+void odph_linux_pthread_join(odph_linux_pthread_t *thread_tbl, int num)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < num; i++) {
+ /* Wait thread to exit */
+ ret = pthread_join(thread_tbl[i].thread, NULL);
+ if (ret != 0) {
+ ODPH_ERR("Failed to join thread from cpu #%d\n",
+ thread_tbl[i].cpu);
+ }
+ pthread_attr_destroy(&thread_tbl[i].attr);
+ }
+}
+
+int odph_linux_process_fork_n(odph_linux_process_t *proc_tbl,
+ const odp_cpumask_t *mask,
+ const odph_linux_thr_params_t *thr_params)
+{
+ pid_t pid;
+ int num;
+ int cpu_count;
+ int cpu;
+ int i;
+
+ num = odp_cpumask_count(mask);
+
+ memset(proc_tbl, 0, num * sizeof(odph_linux_process_t));
+
+ cpu_count = odp_cpu_count();
+
+ if (num < 1 || num > cpu_count) {
+ ODPH_ERR("Bad num\n");
+ return -1;
+ }
+
+ cpu = odp_cpumask_first(mask);
+ for (i = 0; i < num; i++) {
+ cpu_set_t cpu_set;
+
+ CPU_ZERO(&cpu_set);
+ CPU_SET(cpu, &cpu_set);
+
+ pid = fork();
+
+ if (pid < 0) {
+ ODPH_ERR("fork() failed\n");
+ return -1;
+ }
+
+ /* Parent continues to fork */
+ if (pid > 0) {
+ proc_tbl[i].pid = pid;
+ proc_tbl[i].cpu = cpu;
+
+ cpu = odp_cpumask_next(mask, cpu);
+ continue;
+ }
+
+ /* Child process */
+
+ /* Request SIGTERM if parent dies */
+ prctl(PR_SET_PDEATHSIG, SIGTERM);
+ /* Parent died already? */
+ if (getppid() == 1)
+ kill(getpid(), SIGTERM);
+
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set)) {
+ ODPH_ERR("sched_setaffinity() failed\n");
+ return -2;
+ }
+
+ if (odp_init_local(thr_params->instance,
+ thr_params->thr_type)) {
+ ODPH_ERR("Local init failed\n");
+ return -2;
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+int odph_linux_process_fork(odph_linux_process_t *proc, int cpu,
+ const odph_linux_thr_params_t *thr_params)
+{
+ odp_cpumask_t mask;
+
+ odp_cpumask_zero(&mask);
+ odp_cpumask_set(&mask, cpu);
+ return odph_linux_process_fork_n(proc, &mask, thr_params);
+}
+
+int odph_linux_process_wait_n(odph_linux_process_t *proc_tbl, int num)
+{
+ pid_t pid;
+ int i, j;
+ int status = 0;
+
+ for (i = 0; i < num; i++) {
+ pid = wait(&status);
+
+ if (pid < 0) {
+ ODPH_ERR("wait() failed\n");
+ return -1;
+ }
+
+ for (j = 0; j < num; j++) {
+ if (proc_tbl[j].pid == pid) {
+ proc_tbl[j].status = status;
+ break;
+ }
+ }
+
+ if (j == num) {
+ ODPH_ERR("Bad pid:%d\n", (int)pid);
+ return -1;
+ }
+
+ /* Examine the child process' termination status */
+ if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) {
+ ODPH_ERR("Child exit status:%d (pid:%d)\n",
+ WEXITSTATUS(status), (int)pid);
+ return -1;
+ }
+ if (WIFSIGNALED(status)) {
+ int signo = WTERMSIG(status);
+
+ ODPH_ERR("Child term signo:%d - %s (pid:%d)\n",
+ signo, strsignal(signo), (int)pid);
+ return -1;
+ }
+ }
+
+ return 0;
+}