hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*
 * Copyright (C) 2005 Philippe Gerum <rpm@xenomai.org>.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
 
#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <getopt.h>
#include <limits.h>
#include <unistd.h>
#include <stdint.h>
#include <semaphore.h>
#include <boilerplate/setup.h>
#include <cobalt/uapi/kernel/heap.h>
#include <cobalt/ticks.h>
#include <cobalt/tunables.h>
#include <asm/xenomai/syscall.h>
#include <xenomai/init.h>
#include "umm.h"
#include "internal.h"
 
/**
 * @ingroup cobalt
 * @defgroup cobalt_api POSIX interface
 * @anchor cobalt_api
 *
 * The Cobalt/POSIX interface is an implementation of a subset of the
 * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/">
 * Single Unix specification</a> over the Cobalt core.
 *
 * The routines from this subset are implemented as wrapper functions
 * as defined by the linker (--wrap option, see man ld(1)).  The
 * linker flags for enabling symbol wrapping can be obtained from the
 * following command: *xeno-config --posix --ldflags*.
 * The full documentation for *xeno-config* can be found at
 * https://xenomai.org/documentation/xenomai-3/html/man1/xeno-config/index.html.
 *
 * When symbol wrapping is enabled:
 *
 *   - calls to POSIX services for which Cobalt provides a (real-time)
 * implementation are redirected to the library implementing the
 * wrapper, by default libcobalt. A list of wrapped symbols libcobalt
 * overrides can be found in the source tree, in
 * lib/cobalt/cobalt.wrappers.
 *
 * With or without symbol wrapping:
 *
 *   - the wrapper function of a POSIX routine can be explicitly
 * invoked by enclosing the function call with the __RT() macro. Since
 * the wrapper symbol is weak, it may be overriden by a 3rd party
 * library, typically to implement its own version of the POSIX call,
 * instead or on top of libcobalt's. e.g. __RT(sem_init(&sem, 0, 0))
 * would initialize a real-time semaphore, usually from libcobalt
 * unless a stronger sem_init() wrapper has been provided by a 3rd
 * party library.
 *
 *   - the libcobalt implementation of a POSIX routine can be
 * explicitly invoked by enclosing the function call with the
 * __COBALT() macro.  e.g. __COBALT(sem_init(&sem, 0, 0)) would always
 * initialize a Cobalt semaphore (strong symbol).
 *
 *   - the regular *libc implementation of a POSIX routine can be
 * explicitly invoked by enclosing the function call with the __STD()
 * macro. This form basically prevents the symbol wrapping to take
 * place. e.g.  __STD(sem_init(&sem, 0, 0)) would always initialize a
 * regular *libc semaphore. This is strictly equivalent to calling the
 * __real_* form of such routine as documented for ld(1).
 *
 * Qualifying POSIX calls explicitly as described above may prove
 * useful for invoking real-time services selectively within a large
 * POSIX code base, for which globally enabling symbol wrapping would
 * be unpractical. This may also help in implementing real-time
 * service libraries for which depending on the linker's symbol
 * wrapping mechanism is not suitable.
 *
 * This said, conforming to the POSIX standard unspoiled by macro
 * tricks for developing an application may be a significant upside as
 * well. YMMV.
 */
 
__weak int __cobalt_control_bind = 0;
 
int __cobalt_main_prio = -1;
 
struct sigaction __cobalt_orig_sigdebug;
 
static const struct option cobalt_options[] = {
   {
#define main_prio_opt        0
       .name = "main-prio",
       .has_arg = required_argument,
   },
   {
#define print_bufsz_opt    1
       .name = "print-buffer-size",
       .has_arg = required_argument,
   },
   {
#define print_bufcnt_opt    2
       .name = "print-buffer-count",
       .has_arg = required_argument,
   },
   {
#define print_syncdelay_opt    3
       .name = "print-sync-delay",
       .has_arg = required_argument,
   },
   { /* Sentinel */ }
};
 
static void sigill_handler(int sig)
{
   const char m[] = "no Xenomai/cobalt support in kernel?\n";
   ssize_t rc __attribute__ ((unused));
   rc = write(2, m, sizeof(m) - 1);
   exit(EXIT_FAILURE);
}
 
static void low_init(void)
{
   sighandler_t old_sigill_handler;
   struct cobalt_bindreq breq;
   struct cobalt_featinfo *f;
   int ret;
 
   old_sigill_handler = signal(SIGILL, sigill_handler);
   if (old_sigill_handler == SIG_ERR)
       early_panic("signal(SIGILL): %s", strerror(errno));
 
   f = &breq.feat_ret;
   breq.feat_req = XENOMAI_FEAT_DEP;
   if (__cobalt_control_bind)
       breq.feat_req |= __xn_feat_control;
   breq.abi_rev = XENOMAI_ABI_REV;
   ret = XENOMAI_SYSBIND(&breq);
 
   signal(SIGILL, old_sigill_handler);
 
   switch (ret) {
   case 0:
       break;
   case -EINVAL:
       early_panic("missing feature: %s", f->feat_mis_s);
   case -ENOEXEC:
       early_panic("ABI mismatch: required r%lu, provided r%lu",
               XENOMAI_ABI_REV, f->feat_abirev);
   case -EAGAIN:
       early_panic("Cobalt core present but stopped "
               "(use corectl --start)");
   case -ENOSYS:
       early_panic("Cobalt core not enabled in kernel");
   default:
       early_panic("binding failed: %s", strerror(-ret));
   }
 
   trace_me("connected to Cobalt");
 
   if (mlockall(MCL_CURRENT | MCL_FUTURE))
       early_panic("mlockall: %s", strerror(errno));
 
   trace_me("memory locked");
   cobalt_ticks_init(f->clock_freq);
   cobalt_features_init(f);
   cobalt_init_umm(f->vdso_offset);
   trace_me("memory heaps mapped");
   cobalt_init_current_keys();
}
 
static int cobalt_init_2(void);
 
static void cobalt_fork_handler(void)
{
   cobalt_unmap_umm();
   cobalt_clear_tsd();
   cobalt_print_init_atfork();
   if (cobalt_init_2())
       exit(EXIT_FAILURE);
}
 
static inline void commit_stack_memory(void)
{
   char stk[PTHREAD_STACK_MIN / 2];
   cobalt_commit_memory(stk);
}
 
static void cobalt_init_1(void)
{
   struct sigaction sa;
 
   sa.sa_sigaction = cobalt_sigdebug_handler;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = SA_SIGINFO;
   sigaction(SIGDEBUG, &sa, &__cobalt_orig_sigdebug);
 
   /*
    * NOTE: a placeholder for pthread_atfork() may return an
    * error status with uClibc, so we don't check the return
    * value on purpose.
    */
   pthread_atfork(NULL, NULL, cobalt_fork_handler);
 
   if (sizeof(struct cobalt_mutex_shadow) > sizeof(pthread_mutex_t))
       early_panic("sizeof(pthread_mutex_t): %Zd <"
               " sizeof(cobalt_mutex_shadow): %Zd!",
               sizeof(pthread_mutex_t),
               sizeof(struct cobalt_mutex_shadow));
 
   if (sizeof(struct cobalt_cond_shadow) > sizeof(pthread_cond_t))
       early_panic("sizeof(pthread_cond_t): %Zd <"
               " sizeof(cobalt_cond_shadow): %Zd!",
               sizeof(pthread_cond_t),
               sizeof(struct cobalt_cond_shadow));
 
   if (sizeof(struct cobalt_sem_shadow) > sizeof(sem_t))
       early_panic("sizeof(sem_t): %Zd <"
               " sizeof(cobalt_sem_shadow): %Zd!",
               sizeof(sem_t),
               sizeof(struct cobalt_sem_shadow));
}
 
static int cobalt_init_2(void)
{
   pthread_t ptid = pthread_self();
   struct sched_param parm;
   int policy, ret;
 
   commit_stack_memory();    /* We only need this for the main thread */
   cobalt_default_condattr_init();
 
   low_init();
   cobalt_mutex_init();
   cobalt_sched_init();
   cobalt_thread_init();
   cobalt_print_init();
 
   if (__cobalt_control_bind)
       return 0;
 
   ret = __STD(pthread_getschedparam(ptid, &policy, &parm));
   if (ret) {
       early_warning("pthread_getschedparam failed");
       return -ret;
   }
 
   /*
    * Turn the main thread into a Cobalt thread.
    * __cobalt_main_prio might have been overriden by some
    * compilation unit which has been linked in, to force the
    * scheduling parameters. Otherwise, the current policy and
    * priority are reused, for declaring the thread to the
    * Cobalt scheduler.
    *
    * SCHED_FIFO is assumed for __cobalt_main_prio > 0.
    */
   if (__cobalt_main_prio > 0) {
       policy = SCHED_FIFO;
       parm.sched_priority = __cobalt_main_prio;
   } else if (__cobalt_main_prio == 0) {
       policy = SCHED_OTHER;
       parm.sched_priority = 0;
   }
 
   ret = __RT(pthread_setschedparam(ptid, policy, &parm));
   if (ret) {
       early_warning("pthread_setschedparam failed { policy=%d, prio=%d }",
                 policy, parm.sched_priority);
       return -ret;
   }
 
   return 0;
}
 
int cobalt_init(void)
{
   cobalt_init_1();
 
   return cobalt_init_2();
}
 
static int get_int_arg(const char *name, const char *arg,
              int *valp, int min)
{
   int value, ret;
   char *p;
 
   errno = 0;
   value = (int)strtol(arg, &p, 10);
   if (errno || *p || value < min) {
       ret = -errno ?: -EINVAL;
       early_warning("invalid value for %s: %s", name, arg);
       return ret;
   }
 
   *valp = value;
 
   return 0;
}
 
static int cobalt_parse_option(int optnum, const char *optarg)
{
   int value, ret;
 
   switch (optnum) {
   case main_prio_opt:
       ret = get_int_arg("--main-prio", optarg, &value, INT32_MIN);
       if (ret)
           return ret;
       __cobalt_main_prio = value;
       break;
   case print_bufsz_opt:
       ret = get_int_arg("--print-buffer-size", optarg, &value, 0);
       if (ret)
           return ret;
       __cobalt_print_bufsz = value;
       break;
   case print_bufcnt_opt:
       ret = get_int_arg("--print-buffer-count", optarg, &value, 0);
       if (ret)
           return ret;
       __cobalt_print_bufcount = value;
       break;
   case print_syncdelay_opt:
       ret = get_int_arg("--print-sync-delay", optarg, &value, 0);
       if (ret)
           return ret;
       __cobalt_print_syncdelay = value;
       break;
   default:
       /* Paranoid, can't happen. */
       return -EINVAL;
   }
 
   return 0;
}
 
static void cobalt_help(void)
{
   fprintf(stderr, "--main-prio=<prio>        main thread priority\n");
   fprintf(stderr, "--print-buffer-size=<bytes>    size of a print relay buffer (16k)\n");
   fprintf(stderr, "--print-buffer-count=<num>    number of print relay buffers (4)\n");
   fprintf(stderr, "--print-sync-delay=<ms>    max delay of output synchronization (100 ms)\n");
}
 
static struct setup_descriptor cobalt_interface = {
   .name = "cobalt",
   .init = cobalt_init,
   .options = cobalt_options,
   .parse_option = cobalt_parse_option,
   .help = cobalt_help,
};
 
core_setup_call(cobalt_interface);