doc: split build and run instructions in Windows guide
[dpdk.git] / lib / librte_eal / windows / eal.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  */
4
5 #include <fcntl.h>
6 #include <io.h>
7 #include <share.h>
8 #include <sys/stat.h>
9
10 #include <rte_debug.h>
11 #include <rte_eal.h>
12 #include <eal_memcfg.h>
13 #include <rte_errno.h>
14 #include <rte_lcore.h>
15 #include <eal_thread.h>
16 #include <eal_internal_cfg.h>
17 #include <eal_filesystem.h>
18 #include <eal_options.h>
19 #include <eal_private.h>
20 #include <rte_trace_point.h>
21
22 #include "eal_windows.h"
23
24  /* Allow the application to print its usage message too if set */
25 static rte_usage_hook_t rte_application_usage_hook;
26
27 /* define fd variable here, because file needs to be kept open for the
28  * duration of the program, as we hold a write lock on it in the primary proc
29  */
30 static int mem_cfg_fd = -1;
31
32 /* early configuration structure, when memory config is not mmapped */
33 static struct rte_mem_config early_mem_config;
34
35 /* Address of global and public configuration */
36 static struct rte_config rte_config = {
37                 .mem_config = &early_mem_config,
38 };
39
40 /* internal configuration (per-core) */
41 struct lcore_config lcore_config[RTE_MAX_LCORE];
42
43 /* internal configuration */
44 struct internal_config internal_config;
45
46 /* platform-specific runtime dir */
47 static char runtime_dir[PATH_MAX];
48
49 const char *
50 rte_eal_get_runtime_dir(void)
51 {
52         return runtime_dir;
53 }
54
55 /* Return a pointer to the configuration structure */
56 struct rte_config *
57 rte_eal_get_configuration(void)
58 {
59         return &rte_config;
60 }
61
62 /* Detect if we are a primary or a secondary process */
63 enum rte_proc_type_t
64 eal_proc_type_detect(void)
65 {
66         enum rte_proc_type_t ptype = RTE_PROC_PRIMARY;
67         const char *pathname = eal_runtime_config_path();
68
69         /* if we can open the file but not get a write-lock we are a secondary
70          * process. NOTE: if we get a file handle back, we keep that open
71          * and don't close it to prevent a race condition between multiple opens
72          */
73         errno_t err = _sopen_s(&mem_cfg_fd, pathname,
74                 _O_RDWR, _SH_DENYNO, _S_IREAD | _S_IWRITE);
75         if (err == 0) {
76                 OVERLAPPED soverlapped = { 0 };
77                 soverlapped.Offset = sizeof(*rte_config.mem_config);
78                 soverlapped.OffsetHigh = 0;
79
80                 HANDLE hwinfilehandle = (HANDLE)_get_osfhandle(mem_cfg_fd);
81
82                 if (!LockFileEx(hwinfilehandle,
83                         LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0,
84                         sizeof(*rte_config.mem_config), 0, &soverlapped))
85                         ptype = RTE_PROC_SECONDARY;
86         }
87
88         RTE_LOG(INFO, EAL, "Auto-detected process type: %s\n",
89                 ptype == RTE_PROC_PRIMARY ? "PRIMARY" : "SECONDARY");
90
91         return ptype;
92 }
93
94 /* display usage */
95 static void
96 eal_usage(const char *prgname)
97 {
98         printf("\nUsage: %s ", prgname);
99         eal_common_usage();
100         /* Allow the application to print its usage message too
101          * if hook is set
102          */
103         if (rte_application_usage_hook) {
104                 printf("===== Application Usage =====\n\n");
105                 rte_application_usage_hook(prgname);
106         }
107 }
108
109 /* Parse the arguments for --log-level only */
110 static void
111 eal_log_level_parse(int argc, char **argv)
112 {
113         int opt;
114         char **argvopt;
115         int option_index;
116
117         argvopt = argv;
118
119         eal_reset_internal_config(&internal_config);
120
121         while ((opt = getopt_long(argc, argvopt, eal_short_options,
122                 eal_long_options, &option_index)) != EOF) {
123
124                 int ret;
125
126                 /* getopt is not happy, stop right now */
127                 if (opt == '?')
128                         break;
129
130                 ret = (opt == OPT_LOG_LEVEL_NUM) ?
131                         eal_parse_common_option(opt, optarg,
132                                 &internal_config) : 0;
133
134                 /* common parser is not happy */
135                 if (ret < 0)
136                         break;
137         }
138
139         optind = 0; /* reset getopt lib */
140 }
141
142 /* Parse the argument given in the command line of the application */
143 static int
144 eal_parse_args(int argc, char **argv)
145 {
146         int opt, ret;
147         char **argvopt;
148         int option_index;
149         char *prgname = argv[0];
150
151         argvopt = argv;
152
153         while ((opt = getopt_long(argc, argvopt, eal_short_options,
154                 eal_long_options, &option_index)) != EOF) {
155
156                 int ret;
157
158                 /* getopt is not happy, stop right now */
159                 if (opt == '?') {
160                         eal_usage(prgname);
161                         return -1;
162                 }
163
164                 ret = eal_parse_common_option(opt, optarg, &internal_config);
165                 /* common parser is not happy */
166                 if (ret < 0) {
167                         eal_usage(prgname);
168                         return -1;
169                 }
170                 /* common parser handled this option */
171                 if (ret == 0)
172                         continue;
173
174                 switch (opt) {
175                 case 'h':
176                         eal_usage(prgname);
177                         exit(EXIT_SUCCESS);
178                 default:
179                         if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
180                                 RTE_LOG(ERR, EAL, "Option %c is not supported "
181                                         "on Windows\n", opt);
182                         } else if (opt >= OPT_LONG_MIN_NUM &&
183                                 opt < OPT_LONG_MAX_NUM) {
184                                 RTE_LOG(ERR, EAL, "Option %s is not supported "
185                                         "on Windows\n",
186                                         eal_long_options[option_index].name);
187                         } else {
188                                 RTE_LOG(ERR, EAL, "Option %d is not supported "
189                                         "on Windows\n", opt);
190                         }
191                         eal_usage(prgname);
192                         return -1;
193                 }
194         }
195
196         if (eal_adjust_config(&internal_config) != 0)
197                 return -1;
198
199         /* sanity checks */
200         if (eal_check_common_options(&internal_config) != 0) {
201                 eal_usage(prgname);
202                 return -1;
203         }
204
205         if (optind >= 0)
206                 argv[optind - 1] = prgname;
207         ret = optind - 1;
208         optind = 0; /* reset getopt lib */
209         return ret;
210 }
211
212 static int
213 sync_func(void *arg __rte_unused)
214 {
215         return 0;
216 }
217
218 static void
219 rte_eal_init_alert(const char *msg)
220 {
221         fprintf(stderr, "EAL: FATAL: %s\n", msg);
222         RTE_LOG(ERR, EAL, "%s\n", msg);
223 }
224
225 /* Stubs to enable EAL trace point compilation
226  * until eal_common_trace.c can be compiled.
227  */
228
229 RTE_DEFINE_PER_LCORE(volatile int, trace_point_sz);
230 RTE_DEFINE_PER_LCORE(void *, trace_mem);
231
232 void
233 __rte_trace_mem_per_thread_alloc(void)
234 {
235 }
236
237 void
238 __rte_trace_point_emit_field(size_t sz, const char *field,
239         const char *type)
240 {
241         RTE_SET_USED(sz);
242         RTE_SET_USED(field);
243         RTE_SET_USED(type);
244 }
245
246 int
247 __rte_trace_point_register(rte_trace_point_t *trace, const char *name,
248         void (*register_fn)(void))
249 {
250         RTE_SET_USED(trace);
251         RTE_SET_USED(name);
252         RTE_SET_USED(register_fn);
253         return -ENOTSUP;
254 }
255
256 /* Launch threads, called at application init(). */
257 int
258 rte_eal_init(int argc, char **argv)
259 {
260         int i, fctret;
261
262         rte_eal_log_init(NULL, 0);
263
264         eal_log_level_parse(argc, argv);
265
266         if (eal_create_cpu_map() < 0) {
267                 rte_eal_init_alert("Cannot discover CPU and NUMA.");
268                 /* rte_errno is set */
269                 return -1;
270         }
271
272         if (rte_eal_cpu_init() < 0) {
273                 rte_eal_init_alert("Cannot detect lcores.");
274                 rte_errno = ENOTSUP;
275                 return -1;
276         }
277
278         fctret = eal_parse_args(argc, argv);
279         if (fctret < 0)
280                 exit(1);
281
282         eal_thread_init_master(rte_config.master_lcore);
283
284         RTE_LCORE_FOREACH_SLAVE(i) {
285
286                 /*
287                  * create communication pipes between master thread
288                  * and children
289                  */
290                 if (_pipe(lcore_config[i].pipe_master2slave,
291                         sizeof(char), _O_BINARY) < 0)
292                         rte_panic("Cannot create pipe\n");
293                 if (_pipe(lcore_config[i].pipe_slave2master,
294                         sizeof(char), _O_BINARY) < 0)
295                         rte_panic("Cannot create pipe\n");
296
297                 lcore_config[i].state = WAIT;
298
299                 /* create a thread for each lcore */
300                 if (eal_thread_create(&lcore_config[i].thread_id) != 0)
301                         rte_panic("Cannot create thread\n");
302         }
303
304         /*
305          * Launch a dummy function on all slave lcores, so that master lcore
306          * knows they are all ready when this function returns.
307          */
308         rte_eal_mp_remote_launch(sync_func, NULL, SKIP_MASTER);
309         rte_eal_mp_wait_lcore();
310         return fctret;
311 }