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
#ifndef TASK_MANAGER_WORKING_STEALING_H
#define TASK_MANAGER_WORKING_STEALING_H
// Comment for deactivating ws tpool
#define TASK_MANAGER
//#define TASK_MANAGER_CODING
//#define TASK_MANAGER_RU
//#define TASK_MANAGER_UE
//#define TASK_MANAGER_UE_DECODING
//#define TASK_MANAGER_SIM
#include "task.h"
#include <pthread.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#if defined (__i386__) || defined(__x86_64__)
#define pause_or_yield __builtin_ia32_pause
#elif __aarch64__
#define pause_or_yield() asm volatile("yield" ::: "memory")
#else
static_assert(0!=0, "Unknown CPU architecture");
#endif
#if defined (__i386__) || defined(__x86_64__)
#define LEVEL1_DCACHE_LINESIZE 64
#elif __aarch64__
// This is not true for ARM in the general case
// in linux, you can obtain the size at runtime using sysconf (_SC_LEVEL1_DCACHE_LINESIZE)
// in c++ using std::hardware_destructive_interference_size
#define LEVEL1_DCACHE_LINESIZE 64
#else
static_assert(0!=0, "Unknown CPU architecture");
#endif
typedef struct{
// Avoid false sharing
_Alignas(LEVEL1_DCACHE_LINESIZE) _Atomic(int) completed;
} task_status_t;
typedef struct{
uint8_t* buf;
size_t len;
task_status_t* tasks_remaining;
} thread_info_tm_t;
typedef struct{
pthread_t* t_arr;
size_t len_thr;
atomic_uint_fast64_t index;
void* q_arr;
atomic_uint_fast64_t num_task;
// pthread_cond_t wait_cv;
// pthread_mutex_t wait_mtx;
// _Atomic int32_t futex;
// _Atomic bool waiting;
} task_manager_t;
void init_task_manager(task_manager_t* man, uint32_t num_threads);
void free_task_manager(task_manager_t* man, void (*clean)(task_t* args) );
void async_task_manager(task_manager_t* man, task_t t);
//void trigger_all_task_manager(task_manager_t* man);
//
////void trigger_and_spin_task_manager(task_manager_t* man);
//
//void stop_spining_task_manager(task_manager_t* man);
//
////void trigger_and_wait_all_task_manager(task_manager_t* man);
//
//void wait_all_task_manager(task_manager_t* man);
//
// This function does not belong here.
// It should be in an algorithm file
//void wait_spin_all_atomics_one(size_t len, _Atomic int arr[len]);
void wait_task_status_completed(size_t len, task_status_t* arr);
#endif