EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
em_core.c
1/*
2 * Copyright (c) 2015, Nokia Solutions and Networks
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#ifndef _GNU_SOURCE
32#define _GNU_SOURCE
33#endif
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <errno.h>
40#include <limits.h>
41#include <stdbool.h>
42#include <stdint.h>
43#include <stdio.h>
44#include <string.h>
45#include <sys/types.h>
46#include <unistd.h>
47
48#include <odp_api.h>
49
50#include <event_machine.h>
52
53#include "em_core.h"
54#include "em_core_types.h"
55#include "em_error.h"
56#include "em_init.h"
57#include "em_internal_event.h"
59#include "em_libconfig.h"
60#include "em_mem.h"
61
62em_status_t core_map_init(core_map_t *const core_map)
63{
64 memset(core_map, 0, sizeof(core_map_t));
65
66 odp_rwlock_init(&core_map->rwlock);
67 odp_atomic_init_u32(&core_map->current_core_count, 0);
68 odp_atomic_init_u32(&core_map->worker_core_count, 0);
69 odp_atomic_init_u32(&core_map->control_core_count, 0);
70 odp_atomic_init_u32(&core_map->external_thread_count, 0);
71
72 /* Check em_conf_t::core_count */
73 uint32_t max_cores = em_shm->conf.core_count;
74 uint32_t thr_max = MIN(odp_thread_count_max(), ODP_THREAD_COUNT_MAX);
75
76 if (max_cores < 1 || max_cores > EM_MAX_CORES ||
77 thr_max < 1 || max_cores > thr_max) {
78 EM_LOG(EM_LOG_ERR, "Invalid max core_count=%d! EM_MAX_CORES=%u, ODP-thr-max=%d\n",
79 max_cores, EM_MAX_CORES, thr_max);
80 return EM_ERR_TOO_LARGE;
81 }
82
83 /* Check em_conf_t::phys_mask */
84 const em_core_mask_t *allowed_mask = &em_shm->conf.phys_mask;
85 uint32_t mask_count = em_core_mask_count(allowed_mask);
86
87 if (mask_count < 1 || mask_count < max_cores) {
88 char mask_str[EM_CORE_MASK_STRLEN];
89
90 em_core_mask_tostr(mask_str, sizeof(mask_str), allowed_mask);
91 EM_LOG(EM_LOG_ERR, "Invalid phys_mask=%s! set bits=%d < max core_count=%d\n",
92 mask_str, mask_count, max_cores);
93 return EM_ERR_TOO_SMALL;
94 }
95
96 return EM_OK;
97}
98
99/**
100 * Verify the sched affinity for worker and control EM-cores
101 *
102 * Helper to core_map_init_local()
103 */
104static em_status_t verify_sched_affinity(em_core_type_t core_type, pid_t tid,
105 uint32_t max_cores, const em_core_mask_t *allowed_mask)
106{
107 cpu_set_t cpu_set;
108
109 CPU_ZERO(&cpu_set);
110 if (sched_getaffinity(tid, sizeof(cpu_set), &cpu_set) == -1) {
111 EM_LOG(EM_LOG_ERR, "sched_getaffinity() failed: %s (%d)\n",
112 strerror(errno), errno);
113 return EM_ERR_LIB_FAILED;
114 }
115
116 const uint32_t cpu_set_count = CPU_COUNT(&cpu_set);
117
118 if (core_type == EM_CORE_TYPE_WORKER) {
119 if (cpu_set_count != 1) {
120 EM_LOG(EM_LOG_ERR,
121 "EM-core type is WORKER, but cpuset count=%d != 1\n",
122 cpu_set_count);
123 return EM_ERR_BAD_STATE;
124 }
125 } else if (core_type == EM_CORE_TYPE_CONTROL) {
126 if (cpu_set_count > max_cores) {
127 EM_LOG(EM_LOG_ERR,
128 "EM-core type is CONTROL, but cpuset count=%d > max=%d\n",
129 cpu_set_count, max_cores);
130 return EM_ERR_BAD_STATE;
131 }
132
133 em_core_mask_t cpuset_mask;
134 em_core_mask_t or_mask;
135
136 em_core_mask_zero(&cpuset_mask);
137
138 for (int i = 0; i < CPU_SETSIZE; i++) {
139 if (CPU_ISSET(i, &cpu_set))
140 em_core_mask_set(i, &cpuset_mask);
141 }
142
143 /* the 'cpuset_mask' must be subset of em_conf_t::phys_mask */
144 em_core_mask_or(&or_mask, &cpuset_mask, allowed_mask);
145
146 if (!em_core_mask_equal(&or_mask, allowed_mask)) {
147 char cpuset_str[EM_CORE_MASK_STRLEN];
148 char allowed_str[EM_CORE_MASK_STRLEN];
149
150 em_core_mask_tostr(cpuset_str, sizeof(cpuset_str), &cpuset_mask);
151 em_core_mask_tostr(allowed_str, sizeof(allowed_str), allowed_mask);
152
153 EM_LOG(EM_LOG_ERR,
154 "Cpuset of the control EM-core must be subset of conf.phys_mask\n"
155 "cpuset=%s conf.phys_mask=%s\n",
156 cpuset_str, allowed_str);
157 return EM_ERR_BAD_STATE;
158 }
159 } else {
160 EM_LOG(EM_LOG_ERR, "Unsupported EM-core type:%d\n", core_type);
161 return EM_ERR_NOT_FOUND;
162 }
163
164 return EM_OK;
165}
166
167/**
168 * @brief Determine the EM-core id to use for this EM-core
169 *
170 * Helper to core_map_init_local() and must be called with the core_map
171 * RW-lock held: odp_rwlock_write_lock(&core_map->rwlock);
172 *
173 * @param req_core_id Requested core-id or -1 to let EM decide
174 * @param max_cores Max number of allowed EM-cores
175 * @param core_map Core map structure
176 *
177 * @return EM-core id to use or -1 on error
178 */
179static int determine_core_id(int req_core_id, uint32_t max_cores, const core_map_t *core_map)
180{
181 if (unlikely(req_core_id < -1)) {
182 EM_LOG(EM_LOG_ERR,
183 "Requested core-id:%d invalid:\n"
184 " -1: Let EM decide, [0 - %u]: req id range\n",
185 req_core_id, max_cores - 1);
186 return -1;
187 }
188
189 /*
190 * -1: let EM assign the core-id
191 */
192 if (req_core_id == -1) {
193 uint32_t core_id = 0;
194
195 for (; core_id < max_cores; core_id++) {
196 /* Use the first unset bit in the coremask of EM-cores => core-id */
197 if (!em_core_mask_isset(core_id, &core_map->rwlocked.logic_mask))
198 break;
199 }
200 if (unlikely(core_id == max_cores)) {
201 EM_LOG(EM_LOG_ERR, "No free EM-core ids found in range [0 - %u] (max:%u)\n",
202 max_cores - 1, max_cores);
203 return -1;
204 }
205
206 return (int)core_id;
207 }
208
209 /*
210 * Use the requested EM-core id if available (unused).
211 */
212 if ((uint32_t)req_core_id >= max_cores) {
213 EM_LOG(EM_LOG_ERR, "Given core-id:%d too large (max:%u)\n",
214 req_core_id, max_cores - 1);
215 return -1;
216 }
217
218 int unavailable = em_core_mask_isset(req_core_id, &core_map->rwlocked.logic_mask);
219
220 if (unlikely(unavailable)) {
221 EM_LOG(EM_LOG_ERR, "Given core-id:%d already in use\n", req_core_id);
222 return -1;
223 }
224
225 /* The requested EM-core is available, return it. */
226 return req_core_id;
227}
228
229/**
230 * Local init of EM-cores of type EM_CORE_TYPE_WORKER or EM_CORE_TYPE_CONTROL
231 */
232em_status_t core_map_init_local(core_map_t *const core_map, const em_conf_local_t *conf_local)
233{
234 em_locm_t *const locm = &em_locm;
235 const em_core_mask_t *allowed_mask = &em_shm->conf.phys_mask;
236 const uint32_t max_cores = em_shm->conf.core_count; /* <= EM_MAX_CORES */
237 const int phys_core = odp_cpu_id();
238 const pid_t tid = gettid();
239 em_status_t err;
240 int core_id;
241
242 /* Verify that the current physical core/cpu is in the list of allowed ones */
243 if (!em_core_mask_isset(phys_core, allowed_mask)) {
244 char mask_str[EM_CORE_MASK_STRLEN];
245
246 em_core_mask_tostr(mask_str, sizeof(mask_str), allowed_mask);
247 EM_LOG(EM_LOG_ERR, "The used phys_core:%d not allowed by the phys_mask:%s\n",
248 phys_core, mask_str);
249 return EM_ERR_BAD_ID;
250 }
251
252 /* Verify the sched affinity for worker and control EM-cores */
253 err = verify_sched_affinity(conf_local->core_type, tid,
254 max_cores, allowed_mask);
255 if (unlikely(err != EM_OK))
256 return err;
257
258 const int odp_thr = odp_thread_id();
259 const int thr_max = MIN(odp_thread_count_max(), ODP_THREAD_COUNT_MAX);
260
261 if (odp_thr < 0 || odp_thr >= thr_max) {
262 EM_LOG(EM_LOG_ERR, "Invalid ODP thread-id:%d, id range is 0->%d\n",
263 odp_thr, thr_max);
264 return EM_ERR_LIB_FAILED;
265 }
266
267 /* Generate the path to the /proc/[tid]/stat file, store path inside RW-lock */
268 char path[32];
269 size_t path_len;
270
271 snprintf(path, sizeof(path), "/proc/%d/stat", tid);
272 path[sizeof(path) - 1] = '\0';
273 path_len = strnlen(path, sizeof(path));
274
275 if (path_len >= sizeof(path)) {
276 EM_LOG(EM_LOG_ERR, "strnlen(%s)=%zu >= sizeof(path)=%zu\n",
277 path, path_len, sizeof(path));
278 return EM_ERR_LIB_FAILED;
279 }
280 path_len++; /* include the '\0' */
281
282 /*
283 * Lock RW-lock for writing
284 */
285 odp_rwlock_write_lock(&core_map->rwlock);
286
287 /* Set EM-core id */
288 core_id = determine_core_id(conf_local->core_id /* requested */, max_cores, core_map);
289 if (unlikely(core_id < 0)) {
290 /* Unlock RW-lock on error, writing done */
291 odp_rwlock_write_unlock(&core_map->rwlock);
292 return EM_ERR_TOO_SMALL;
293 }
294 locm->core_id = core_id;
295
296 uint32_t current_core_count = odp_atomic_fetch_inc_u32(&core_map->current_core_count) + 1;
297
298 if (unlikely(current_core_count > max_cores)) {
299 /* Roll back core count on error*/
300 odp_atomic_dec_u32(&core_map->current_core_count);
301 /* Unlock RW-lock on error, writing done */
302 odp_rwlock_write_unlock(&core_map->rwlock);
303 EM_LOG(EM_LOG_ERR, "Current core count:%d too large (max:%d)\n",
304 current_core_count, max_cores);
305 return EM_ERR_TOO_LARGE;
306 }
307
308 core_map->rwlocked.thr_vs_logic.logic[odp_thr] = (uint8_t)core_id;
309 core_map->rwlocked.thr_vs_logic.odp_thr[core_id] = (uint16_t)odp_thr;
310 core_map->rwlocked.tids[core_id] = tid;
311 core_map->rwlocked.core_types[core_id] = conf_local->core_type;
312
313 em_core_mask_set(core_id, &core_map->rwlocked.logic_mask);
314 odp_thrmask_set(&core_map->rwlocked.thrmask_emcores, odp_thr);
315 odp_thrmask_set(&core_map->rwlocked.thrmask_all, odp_thr);
316
317 if (conf_local->core_type == EM_CORE_TYPE_WORKER) {
318 odp_atomic_inc_u32(&core_map->worker_core_count);
319 em_core_mask_set(core_id, &core_map->rwlocked.worker_mask);
320 } else {
321 odp_atomic_inc_u32(&core_map->control_core_count);
322 em_core_mask_set(core_id, &core_map->rwlocked.control_mask);
323 }
324
325 /* store the /proc/[tid]/stat file path */
326 memcpy(core_map->rwlocked.proc_tid_stat_paths[core_id], path, path_len);
327
328 /*
329 * Unlock RW-lock, writing done
330 */
331 odp_rwlock_write_unlock(&core_map->rwlock);
332
333 DBG_PRINT("EM-core%02d (%s): %s() - EM-cores:%d (workers:%u ctrl:%u), EM-ext-thrs:%u\n",
334 core_id, __func__, conf_local->core_type == EM_CORE_TYPE_WORKER ? "WRK" : "CTL",
335 current_core_count, odp_atomic_load_u32(&core_map->worker_core_count),
336 odp_atomic_load_u32(&core_map->control_core_count),
337 odp_atomic_load_u32(&core_map->external_thread_count));
338
339 return EM_OK;
340}
341
342/**
343 * Local init of an EM external thread/process, EM_CORE_TYPE_EXT
344 */
345em_status_t core_map_init_extthr(core_map_t *const core_map)
346{
347 em_locm_t *const locm = &em_locm;
348 const int odp_thr = odp_thread_id();
349 const int thr_max = MIN(odp_thread_count_max(), ODP_THREAD_COUNT_MAX);
350 const pid_t tid = gettid();
351
352 locm->core_id = -1;
353
354 if (odp_thr < 0 || odp_thr >= thr_max) {
355 EM_LOG(EM_LOG_ERR,
356 "Ext-thread: Invalid ODP thread-id:%d, id range is 0->%d\n",
357 odp_thr, thr_max);
358 return EM_ERR_LIB_FAILED;
359 }
360
361 /*
362 * Lock RW-lock for writing
363 */
364 odp_rwlock_write_lock(&core_map->rwlock);
365
366 odp_atomic_inc_u32(&core_map->external_thread_count);
367 odp_thrmask_set(&core_map->rwlocked.thrmask_extthrs, odp_thr);
368 odp_thrmask_set(&core_map->rwlocked.thrmask_all, odp_thr);
369 core_map->rwlocked.ext_tids[odp_thr] = tid;
370
371 /*
372 * Unlock RW-lock, writing done
373 */
374 odp_rwlock_write_unlock(&core_map->rwlock);
375
376 DBG_PRINT("EM-extthr%02d (EXT): %s() - EM-cores:%d (workers:%u ctrl:%u), EM-ext-thrs:%u\n",
377 odp_thr, __func__, odp_atomic_load_u32(&core_map->current_core_count),
378 odp_atomic_load_u32(&core_map->worker_core_count),
379 odp_atomic_load_u32(&core_map->control_core_count),
380 odp_atomic_load_u32(&core_map->external_thread_count));
381
382 return EM_OK;
383}
384
385/**
386 * EM internal event handler (see em_internal_event.c&h)
387 * Handle the internal event notifying the EM-cores about a thread termination
388 * (internal event id: TERM_THREAD_REQ).
389 */
390void i_event__term_thread_req(const internal_event_t *i_ev)
391{
392 const int thr = odp_thread_id();
393 int32_t cnt = odp_atomic_fetch_dec_u32(&em_shm->core_map.ongoing_term_reqs[thr]);
394
396 DBG_PRINT("EM-core%02d (thr%02d): TERM_THREAD_REQ from thr%02d - ongoing-term-reqs=%d\n",
397 em_core_id(), thr, i_ev->term_thread.thr, cnt);
398 else
399 DBG_PRINT("EM-extthr%02d: TERM_THREAD_REQ from thr%02d - ongoing-term-reqs=%d\n",
400 thr, i_ev->term_thread.thr, cnt);
401
402 if (unlikely(cnt < 0)) {
403 INTERNAL_ERROR(EM_ERR_TOO_SMALL, EM_ESCOPE_INTERNAL_EVENT_RECV_FUNC,
404 "TERM_THREAD_REQ - ongoing-term-reqs=%d", i_ev->id, cnt);
405 }
406}
407
408/**
409 * Done-callback for the internal TERM_THREAD_REQ
410 *
411 * Function run when all receivers of the TERM_THREAD_REQ-events
412 * have processed the requests.
413 */
414static void term_thread_req_done_callback(void *arg)
415{
416 (void)arg;
417
419
421 DBG_PRINT("EM-core%02d (thr%02d): TERM_THREAD_REQ DONE\n",
422 em_core_id(), odp_thread_id());
423 else
424 DBG_PRINT("EM-extthr%02d: TERM_THREAD_REQ DONE\n",
425 odp_thread_id());
426}
427
428/**
429 * Allocate and send TERM_THREAD_REQ events to all remaining EM-cores
430 */
431static em_status_t
432term_thread_req(int thread_id, const odp_thrmask_t *remain_thrmask_emcores, em_escope_t escope)
433{
434 em_event_t event = em_alloc(sizeof(internal_event_t),
437 EM_ERR_ALLOC_FAILED, escope,
438 "Internal event (TERM_THREAD_REQ) allocation failed");
439
440 internal_event_t *i_event = em_event_pointer(event);
441
442 i_event->id = TERM_THREAD_REQ;
443 i_event->term_thread.thr = thread_id;
444
445 int err = send_core_ctrl_events(remain_thrmask_emcores, event,
446 term_thread_req_done_callback, NULL,
447 0, NULL, true);
448 if (unlikely(err)) {
449 char mask_str[ODP_THRMASK_STR_SIZE];
450
451 odp_thrmask_to_str(remain_thrmask_emcores, mask_str, ODP_THRMASK_STR_SIZE);
452 return INTERNAL_ERROR(EM_ERR_LIB_FAILED, escope,
453 "send_core_ctrl_events(mask=%s) failed", mask_str);
454 }
455
456 return EM_OK;
457}
458
459int core_map_term_local(core_map_t *const core_map, em_escope_t escope)
460{
461 const em_locm_t *const locm = &em_locm;
462 const int32_t core_id = locm->core_id;
463 const int odp_thr = odp_thread_id();
464 odp_thrmask_t remain_thrmask_emcores;
465 em_status_t stat = EM_OK;
466
467 /*
468 * Lock RW-lock for writing
469 */
470 odp_rwlock_write_lock(&core_map->rwlock);
471
472 int32_t current_core_count = odp_atomic_fetch_dec_u32(&core_map->current_core_count) - 1;
473
474 core_map->rwlocked.thr_vs_logic.logic[odp_thr] = 0; /* EM core-id */
475 core_map->rwlocked.thr_vs_logic.odp_thr[core_id] = 0; /* odp thread-id */
476
477 em_core_mask_clr(core_id, &core_map->rwlocked.logic_mask);
479 odp_atomic_dec_u32(&core_map->worker_core_count);
480 em_core_mask_clr(core_id, &core_map->rwlocked.worker_mask);
481 } else {
482 odp_atomic_dec_u32(&core_map->control_core_count);
483 em_core_mask_clr(core_id, &core_map->rwlocked.control_mask);
484 }
485 odp_thrmask_clr(&core_map->rwlocked.thrmask_emcores, odp_thr);
486 odp_thrmask_clr(&core_map->rwlocked.thrmask_all, odp_thr);
487
488 odp_thrmask_copy(&remain_thrmask_emcores, &core_map->rwlocked.thrmask_emcores);
489
490 if (current_core_count > 0) {
491 int thr = odp_thrmask_first(&remain_thrmask_emcores);
492
493 while (thr >= 0) {
494 odp_atomic_inc_u32(&core_map->ongoing_term_reqs[thr]);
495 thr = odp_thrmask_next(&remain_thrmask_emcores, thr);
496 }
497 }
498
499 core_map->rwlocked.tids[core_id] = 0;
500 core_map->rwlocked.core_types[core_id] = EM_CORE_TYPE_UNDEF;
501 core_map->rwlocked.proc_tid_stat_paths[core_id][0] = '\0';
502
503 if (current_core_count >= 1)
504 stat = term_thread_req(odp_thr, &remain_thrmask_emcores, escope);
505
506 /*
507 * Unlock RW-lock, writing done
508 */
509 odp_rwlock_write_unlock(&core_map->rwlock);
510
511 if (stat != EM_OK)
512 (void)INTERNAL_ERROR(stat, escope, "term_thread_req() failed");
513
514 if (current_core_count < 1) {
515 /* Last core manually calls the term-done function */
516 term_thread_req_done_callback(NULL);
517 }
518
519 if (unlikely(current_core_count < 0))
520 EM_LOG(EM_LOG_ERR, "Current core count invalid: %d", current_core_count);
521
522 DBG_PRINT("EM-core%02d (thr%02d): %s() - current core count:%d\n",
523 locm->core_id, odp_thr, __func__, current_core_count);
524
525 return current_core_count;
526}
527
528int core_map_term_extthr(core_map_t *const core_map, em_escope_t escope)
529{
530 const int odp_thr = odp_thread_id();
531 odp_thrmask_t remain_thrmask_emcores;
532 em_status_t stat = EM_OK;
533
534 /*
535 * Lock RW-lock for writing
536 */
537 odp_rwlock_write_lock(&core_map->rwlock);
538
539 int32_t current_core_count = odp_atomic_load_u32(&core_map->current_core_count);
540
541 odp_atomic_dec_u32(&core_map->external_thread_count);
542 odp_thrmask_clr(&core_map->rwlocked.thrmask_extthrs, odp_thr);
543 odp_thrmask_clr(&core_map->rwlocked.thrmask_all, odp_thr);
544
545 odp_thrmask_copy(&remain_thrmask_emcores, &core_map->rwlocked.thrmask_emcores);
546
547 if (current_core_count > 0) {
548 int thr = odp_thrmask_first(&remain_thrmask_emcores);
549
550 while (thr >= 0) {
551 odp_atomic_inc_u32(&core_map->ongoing_term_reqs[thr]);
552 thr = odp_thrmask_next(&remain_thrmask_emcores, thr);
553 }
554 }
555 odp_atomic_inc_u32(&core_map->ongoing_term_reqs[odp_thr]);
556
557 core_map->rwlocked.ext_tids[odp_thr] = 0;
558
559 if (current_core_count >= 1)
560 stat = term_thread_req(odp_thr, &remain_thrmask_emcores, escope);
561
562 /*
563 * Unlock RW-lock, writing done
564 */
565 odp_rwlock_write_unlock(&core_map->rwlock);
566
567 if (stat != EM_OK)
568 (void)INTERNAL_ERROR(stat, escope, "term_thread_req() failed");
569
570 if (current_core_count < 1) {
571 /* No EM-cores running (worker or control), call the term-done function */
572 term_thread_req_done_callback(NULL);
573 }
574
575 if (unlikely(current_core_count < 0)) {
576 EM_LOG(EM_LOG_ERR, "Current core count invalid: %d", current_core_count);
577 return -1;
578 }
579
580 DBG_PRINT("EM-extthr%02d: %s() - current EM-core count:%d\n",
581 odp_thr, __func__, current_core_count);
582
583 return current_core_count;
584}
585
586void mask_em2odp__rwlocked(const em_core_mask_t *const core_mask,
587 odp_thrmask_t *const odp_thrmask /*out*/)
588{
589 const core_map_t *const core_map = &em_shm->core_map;
590
591 odp_thrmask_zero(odp_thrmask);
592
593 /* Assumes lock is already taken: odp_rwlock_read_lock(&em_shm->core_map.rwlock) */
594 int core = em_core_mask_first(core_mask);
595
596 while (core >= 0) {
597 int odp_thread_id = core_map->rwlocked.thr_vs_logic.odp_thr[core];
598
599 odp_thrmask_set(odp_thrmask, odp_thread_id);
600 core = em_core_mask_next(core_mask, core);
601 }
602
603 /* Assumes lock is unlocked by caller: odp_rwlock_read_unlock(&em_shm->core_map.rwlock); */
604}
605
606void mask_em2odp(const em_core_mask_t *const core_mask,
607 odp_thrmask_t *const odp_thrmask /*out*/)
608{
609 core_map_t *const core_map = &em_shm->core_map;
610
611 odp_thrmask_zero(odp_thrmask);
612
613 odp_rwlock_read_lock(&core_map->rwlock);
614
615 int core = em_core_mask_first(core_mask);
616
617 while (core >= 0) {
618 int odp_thread_id = core_map->rwlocked.thr_vs_logic.odp_thr[core];
619
620 odp_thrmask_set(odp_thrmask, odp_thread_id);
621 core = em_core_mask_next(core_mask, core);
622 }
623
624 odp_rwlock_read_unlock(&core_map->rwlock);
625}
626
627/**
628 * @brief Get the CPU ID from the /proc/[tid]/stat file.
629 *
630 * This function reads the CPU ID from the specified file, which is expected to
631 * be in the format of /proc/[tid]/stat. The CPU ID is the 39th field in the
632 * file and indicates the CPU number the thread was last executed on.
633 *
634 * @param proc_tid_stat_file A file pointer to the /proc/[tid]/stat file.
635 * @return The CPU ID the thread was last executed on, or -1 if an error occurs.
636 */
637int read_proc_cpuid(FILE *proc_tid_stat_file)
638{
639 if (unlikely(!proc_tid_stat_file))
640 return -1;
641
642 /* field 39 in the /proc/[tid]/stat file contains the CPU ID */
643 const int cpu_field_idx = 39;
644 int cpu_id = -1;
645 char buffer[512];
646
647 if (likely(fgets(buffer, sizeof(buffer), proc_tid_stat_file) != NULL)) {
648 const char *stat_token;
649 char *saveptr;
650
651 stat_token = strtok_r(buffer, " ", &saveptr);
652
653 /* Scan through to the 'cpu_field_idx' field */
654 for (int i = 1; i < cpu_field_idx; i++) {
655 if (unlikely(!stat_token))
656 break;
657 stat_token = strtok_r(NULL, " ", &saveptr);
658 }
659
660 /* The 'cpu_field_idx':th field contains the CPU number last executed on */
661 if (likely(stat_token)) {
662 char *endptr;
663 long value = strtol(stat_token, &endptr, 10); /* Read CPU ID (39th field) */
664
665 /* Check for conversion errors */
666 if (endptr != stat_token && *endptr == '\0' &&
667 value >= 0 && value <= INT_MAX)
668 cpu_id = (int)value;
669
670 /* Conversion error or out-of-range value keeps cpu_id = -1 */
671 }
672 }
673
674 return cpu_id;
675}
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition em_error.h:58
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition em_error.h:65
int send_core_ctrl_events(const odp_thrmask_t *const thr_mask, em_event_t ctrl_event, void(*f_done_callback)(void *arg_ptr), void *f_done_arg_ptr, int num_notif, const em_notif_t notif_tbl[], bool sync_operation)
Sends an internal control event to each thread set in 'mask'.
ENV_LOCAL em_locm_t em_locm
em_shm_t * em_shm
#define EM_POOL_DEFAULT
#define EM_MAX_CORES
void em_core_mask_or(em_core_mask_t *dst, const em_core_mask_t *src1, const em_core_mask_t *src2)
int em_core_mask_equal(const em_core_mask_t *mask1, const em_core_mask_t *mask2)
int em_core_mask_count(const em_core_mask_t *mask)
void em_core_mask_tostr(char *mask_str, int len, const em_core_mask_t *mask)
int em_core_mask_first(const em_core_mask_t *mask)
void em_core_mask_set(int core, em_core_mask_t *mask)
void em_core_mask_clr(int core, em_core_mask_t *mask)
int em_core_mask_isset(int core, const em_core_mask_t *mask)
int em_core_mask_next(const em_core_mask_t *mask, int idx)
#define EM_CORE_MASK_STRLEN
void em_core_mask_zero(em_core_mask_t *mask)
#define EM_EVENT_UNDEF
int em_core_id(void)
em_core_type_t
@ EM_CORE_TYPE_CONTROL
@ EM_CORE_TYPE_UNDEF
@ EM_CORE_TYPE_WORKER
#define EM_OK
uint32_t em_escope_t
uint32_t em_status_t
@ EM_ERR_NOT_FOUND
@ EM_ERR_TOO_LARGE
@ EM_ERR_BAD_ID
@ EM_ERR_TOO_SMALL
@ EM_ERR_ALLOC_FAILED
@ EM_ERR_BAD_STATE
@ EM_ERR_LIB_FAILED
em_event_t em_alloc(uint32_t size, em_event_type_t type, em_pool_t pool)
void * em_event_pointer(em_event_t event)
@ EM_EVENT_TYPE_SW
odp_atomic_u32_t external_thread_count
odp_rwlock_t rwlock
char proc_tid_stat_paths[EM_MAX_CORES][32]
uint8_t logic[ODP_THREAD_COUNT_MAX]
em_core_type_t core_types[EM_MAX_CORES]
pid_t ext_tids[ODP_THREAD_COUNT_MAX]
odp_atomic_u32_t current_core_count
uint16_t odp_thr[EM_MAX_CORES]
odp_atomic_u32_t worker_core_count
odp_atomic_u32_t ongoing_term_reqs[ODP_THREAD_COUNT_MAX]
odp_thrmask_t thrmask_extthrs
odp_thrmask_t thrmask_all
odp_thrmask_t thrmask_emcores
em_core_mask_t logic_mask
odp_atomic_u32_t control_core_count
em_core_mask_t worker_mask
em_core_mask_t control_mask
pid_t tids[EM_MAX_CORES]
em_core_type_t core_type
uint32_t core_count
em_core_mask_t phys_mask
bool is_em_core
Definition em_mem.h:254
bool is_term_thread_done
Definition em_mem.h:258
em_conf_local_t conf_local
Definition em_mem.h:295
int core_id
Definition em_mem.h:239
em_conf_t conf
Definition em_mem.h:93
struct internal_event_t::@52 term_thread