/* Copyright (c) 2013-2018, Linaro Limited * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct { _odp_thread_state_t thr[ODP_THREAD_COUNT_MAX]; struct { odp_thrmask_t all; odp_thrmask_t worker; odp_thrmask_t control; }; uint32_t num; uint32_t num_worker; uint32_t num_control; odp_spinlock_t lock; } thread_globals_t; /* Globals */ static thread_globals_t *thread_globals; #include /* Thread local */ __thread _odp_thread_state_t *_odp_this_thread; #include int odp_thread_init_global(void) { odp_shm_t shm; shm = odp_shm_reserve("odp_thread_globals", sizeof(thread_globals_t), ODP_CACHE_LINE_SIZE, 0); thread_globals = odp_shm_addr(shm); if (thread_globals == NULL) return -1; memset(thread_globals, 0, sizeof(thread_globals_t)); odp_spinlock_init(&thread_globals->lock); return 0; } int odp_thread_term_global(void) { int ret; ret = odp_shm_free(odp_shm_lookup("odp_thread_globals")); if (ret < 0) ODP_ERR("shm free failed for odp_thread_globals"); return ret; } static int alloc_id(odp_thread_type_t type) { int thr; odp_thrmask_t *all = &thread_globals->all; if (thread_globals->num >= ODP_THREAD_COUNT_MAX) return -1; for (thr = 0; thr < ODP_THREAD_COUNT_MAX; thr++) { if (odp_thrmask_isset(all, thr) == 0) { odp_thrmask_set(all, thr); if (type == ODP_THREAD_WORKER) { odp_thrmask_set(&thread_globals->worker, thr); thread_globals->num_worker++; } else { odp_thrmask_set(&thread_globals->control, thr); thread_globals->num_control++; } thread_globals->num++; return thr; } } return -2; } static int free_id(int thr) { odp_thrmask_t *all = &thread_globals->all; if (thr < 0 || thr >= ODP_THREAD_COUNT_MAX) return -1; if (odp_thrmask_isset(all, thr) == 0) return -1; odp_thrmask_clr(all, thr); if (thread_globals->thr[thr].type == ODP_THREAD_WORKER) { odp_thrmask_clr(&thread_globals->worker, thr); thread_globals->num_worker--; } else { odp_thrmask_clr(&thread_globals->control, thr); thread_globals->num_control--; } thread_globals->num--; return thread_globals->num; } int odp_thread_init_local(odp_thread_type_t type) { int id; int cpu; struct rte_config *cfg = rte_eal_get_configuration(); odp_spinlock_lock(&thread_globals->lock); id = alloc_id(type); odp_spinlock_unlock(&thread_globals->lock); if (id < 0) { ODP_ERR("Too many threads\n"); return -1; } cpu = sched_getcpu(); if (cpu < 0) { ODP_ERR("getcpu failed\n"); return -1; } thread_globals->thr[id].thr = id; thread_globals->thr[id].cpu = cpu; thread_globals->thr[id].type = type; RTE_PER_LCORE(_lcore_id) = cpu; if (cfg->lcore_role[cpu] == ROLE_RTE) ODP_ERR("There is a thread already running on core %d\n", cpu); cfg->lcore_role[cpu] = ROLE_RTE; _odp_this_thread = &thread_globals->thr[id]; sched_fn->thr_add(ODP_SCHED_GROUP_ALL, id); if (type == ODP_THREAD_WORKER) sched_fn->thr_add(ODP_SCHED_GROUP_WORKER, id); else if (type == ODP_THREAD_CONTROL) sched_fn->thr_add(ODP_SCHED_GROUP_CONTROL, id); return 0; } int odp_thread_term_local(void) { int num; int id = _odp_this_thread->thr; odp_thread_type_t type = _odp_this_thread->type; sched_fn->thr_rem(ODP_SCHED_GROUP_ALL, id); if (type == ODP_THREAD_WORKER) sched_fn->thr_rem(ODP_SCHED_GROUP_WORKER, id); else if (type == ODP_THREAD_CONTROL) sched_fn->thr_rem(ODP_SCHED_GROUP_CONTROL, id); odp_spinlock_lock(&thread_globals->lock); num = free_id(id); odp_spinlock_unlock(&thread_globals->lock); if (num < 0) { ODP_ERR("failed to free thread id %i", id); return -1; } return num; /* return a number of threads left */ } int odp_thread_count(void) { return thread_globals->num; } int odp_thread_count_max(void) { return ODP_THREAD_COUNT_MAX; } int odp_thrmask_worker(odp_thrmask_t *mask) { odp_thrmask_copy(mask, &thread_globals->worker); return thread_globals->num_worker; } int odp_thrmask_control(odp_thrmask_t *mask) { odp_thrmask_copy(mask, &thread_globals->control); return thread_globals->num_control; }