eal/windows: add minimum viable code
[dpdk.git] / lib / librte_eal / windows / eal / eal_thread.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  */
4
5 #include <io.h>
6
7 #include <rte_atomic.h>
8 #include <rte_debug.h>
9 #include <rte_launch.h>
10 #include <rte_lcore.h>
11 #include <rte_per_lcore.h>
12 #include <rte_common.h>
13 #include <eal_thread.h>
14
15
16 RTE_DEFINE_PER_LCORE(unsigned int, _lcore_id) = LCORE_ID_ANY;
17
18 /*
19  * Send a message to a slave lcore identified by slave_id to call a
20  * function f with argument arg. Once the execution is done, the
21  * remote lcore switch in FINISHED state.
22  */
23 int
24 rte_eal_remote_launch(lcore_function_t *f, void *arg, unsigned int slave_id)
25 {
26         int n;
27         char c = 0;
28         int m2s = lcore_config[slave_id].pipe_master2slave[1];
29         int s2m = lcore_config[slave_id].pipe_slave2master[0];
30
31         if (lcore_config[slave_id].state != WAIT)
32                 return -EBUSY;
33
34         lcore_config[slave_id].f = f;
35         lcore_config[slave_id].arg = arg;
36
37         /* send message */
38         n = 0;
39         while (n == 0 || (n < 0 && errno == EINTR))
40                 n = _write(m2s, &c, 1);
41         if (n < 0)
42                 rte_panic("cannot write on configuration pipe\n");
43
44         /* wait ack */
45         do {
46                 n = _read(s2m, &c, 1);
47         } while (n < 0 && errno == EINTR);
48
49         if (n <= 0)
50                 rte_panic("cannot read on configuration pipe\n");
51
52         return 0;
53 }
54
55 void
56 eal_thread_init_master(unsigned int lcore_id)
57 {
58         /* set the lcore ID in per-lcore memory area */
59         RTE_PER_LCORE(_lcore_id) = lcore_id;
60 }
61
62 static inline pthread_t
63 eal_thread_self(void)
64 {
65         return GetCurrentThreadId();
66 }
67
68 /* main loop of threads */
69 void *
70 eal_thread_loop(void *arg __rte_unused)
71 {
72         char c;
73         int n, ret;
74         unsigned int lcore_id;
75         pthread_t thread_id;
76         int m2s, s2m;
77         char cpuset[RTE_CPU_AFFINITY_STR_LEN];
78
79         thread_id = eal_thread_self();
80
81         /* retrieve our lcore_id from the configuration structure */
82         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
83                 if (thread_id == lcore_config[lcore_id].thread_id)
84                         break;
85         }
86         if (lcore_id == RTE_MAX_LCORE)
87                 rte_panic("cannot retrieve lcore id\n");
88
89         m2s = lcore_config[lcore_id].pipe_master2slave[0];
90         s2m = lcore_config[lcore_id].pipe_slave2master[1];
91
92         /* set the lcore ID in per-lcore memory area */
93         RTE_PER_LCORE(_lcore_id) = lcore_id;
94
95         RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%zx;cpuset=[%s])\n",
96                 lcore_id, (uintptr_t)thread_id, cpuset);
97
98         /* read on our pipe to get commands */
99         while (1) {
100                 void *fct_arg;
101
102                 /* wait command */
103                 do {
104                         n = _read(m2s, &c, 1);
105                 } while (n < 0 && errno == EINTR);
106
107                 if (n <= 0)
108                         rte_panic("cannot read on configuration pipe\n");
109
110                 lcore_config[lcore_id].state = RUNNING;
111
112                 /* send ack */
113                 n = 0;
114                 while (n == 0 || (n < 0 && errno == EINTR))
115                         n = _write(s2m, &c, 1);
116                 if (n < 0)
117                         rte_panic("cannot write on configuration pipe\n");
118
119                 if (lcore_config[lcore_id].f == NULL)
120                         rte_panic("NULL function pointer\n");
121
122                 /* call the function and store the return value */
123                 fct_arg = lcore_config[lcore_id].arg;
124                 ret = lcore_config[lcore_id].f(fct_arg);
125                 lcore_config[lcore_id].ret = ret;
126                 rte_wmb();
127
128                 /* when a service core returns, it should go directly to WAIT
129                  * state, because the application will not lcore_wait() for it.
130                  */
131                 if (lcore_config[lcore_id].core_role == ROLE_SERVICE)
132                         lcore_config[lcore_id].state = WAIT;
133                 else
134                         lcore_config[lcore_id].state = FINISHED;
135         }
136 }
137
138 /* function to create threads */
139 int
140 eal_thread_create(pthread_t *thread)
141 {
142         HANDLE th;
143
144         th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)eal_thread_loop,
145                                                 NULL, 0, (LPDWORD)thread);
146         if (!th)
147                 return -1;
148
149         SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
150         SetThreadPriority(th, THREAD_PRIORITY_TIME_CRITICAL);
151
152         return 0;
153 }