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
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
/*
 * Copyright (C) 2008 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.
 */
 
#ifndef _COPPERPLATE_THREADOBJ_H
#define _COPPERPLATE_THREADOBJ_H
 
#include <time.h>
#include <semaphore.h>
#include <signal.h>
#include <pthread.h>
#include <stdint.h>
#include <boilerplate/list.h>
#include <boilerplate/lock.h>
#include <boilerplate/sched.h>
#include <copperplate/clockobj.h>
#include <copperplate/heapobj.h>
 
#ifdef CONFIG_XENO_COBALT
 
#include <cobalt/uapi/kernel/types.h>
 
struct xnthread_user_window;
 
struct threadobj_corespec {
   xnhandle_t handle;
   union {
       __u32 u_winoff;
       struct xnthread_user_window *u_window;
   };
};
 
struct threadobj_stat {
   /** Execution time in primary mode (ns). */
   ticks_t xtime;
   /** Current timeout value (ns). */
   ticks_t timeout;
   /** Number of primary->secondary mode switches. */
   uint64_t msw;
   /** Number of context switches. */
   uint64_t csw;
   /** Number of Xenomai syscalls. */
   uint64_t xsc;
   /** Current CPU for thread. */
   int cpu;
   /** Scheduler lock nesting count. */
   int schedlock;
   /** Cobalt thread status bits. */
   unsigned int status;
   /** Number of page faults. */
   uint32_t pf;
};
 
#define SCHED_CORE  SCHED_COBALT
 
static inline
void threadobj_save_timeout(struct threadobj_corespec *corespec,
               const struct timespec *timeout)
{
   /*
    * We retrieve this information from the nucleus directly via
    * cobalt_thread_stat().
    */
}
 
#ifdef CONFIG_XENO_PSHARED
 
static inline struct xnthread_user_window *
threadobj_get_window(struct threadobj_corespec *corespec)
{
   extern void *cobalt_umm_shared;
   return (struct xnthread_user_window *)
       ((caddr_t)cobalt_umm_shared + corespec->u_winoff);
}
 
#else /* !CONFIG_XENO_PSHARED */
 
static inline struct xnthread_user_window *
threadobj_get_window(struct threadobj_corespec *corespec)
{
   return corespec->u_window;
}
 
#endif /* !CONFIG_XENO_PSHARED */
 
#else  /* CONFIG_XENO_MERCURY */
 
#include <sys/time.h>
 
struct threadobj_corespec {
   pthread_cond_t grant_sync;
   int policy_unlocked;
   struct sched_param_ex schedparam_unlocked;
   timer_t rr_timer;
   /** Timeout reported by sysregd. */
   struct timespec timeout;
#ifdef CONFIG_XENO_WORKAROUND_CONDVAR_PI
   int policy_unboosted;
   struct sched_param_ex schedparam_unboosted;
#endif
};
 
struct threadobj_stat {
   /** Current timeout value (ns). */
   ticks_t timeout;
   /** Current CPU for thread. */
   int cpu;
   /** Scheduler lock nesting count. */
   int schedlock;
   /** Mercury thread status bits. */
   unsigned int status;
};
 
#define SCHED_CORE  SCHED_FIFO
 
static inline
void threadobj_save_timeout(struct threadobj_corespec *corespec,
               const struct timespec *timeout)
{
   if (timeout)
       corespec->timeout = *timeout;
}
 
#endif /* CONFIG_XENO_MERCURY */
 
/*
 * threadobj->status, updated with ->lock held.
 */
#define __THREAD_S_STARTED    (1 << 0)    /* threadobj_start() called. */
#define __THREAD_S_WARMUP    (1 << 1)    /* threadobj_prologue() not called yet. */
#define __THREAD_S_ABORTED    (1 << 2)    /* Cancelled before start. */
#define __THREAD_S_LOCKED    (1 << 3)    /* threadobj_lock() granted (debug only). */
#define __THREAD_S_ACTIVE    (1 << 4)    /* Running user code. */
#define __THREAD_S_SUSPENDED    (1 << 5)    /* Suspended via threadobj_suspend(). */
#define __THREAD_S_SAFE        (1 << 6)    /* TCB release deferred. */
#define __THREAD_S_PERIODIC    (1 << 7)    /* Periodic timer set. */
#define __THREAD_S_DEBUG    (1 << 31)    /* Debug mode enabled. */
/*
 * threadobj->run_state, locklessly updated by "current", merged
 * with ->status bits by threadobj_get_status().
 */
#define __THREAD_S_RUNNING    0
#define __THREAD_S_DORMANT    (1 << 16)
#define __THREAD_S_WAIT        (1 << 17)
#define __THREAD_S_TIMEDWAIT    (1 << 18)
#define __THREAD_S_DELAYED    (1 << 19)
#define __THREAD_S_BREAK    (__THREAD_S_DELAYED|(1 << 20))
 
/* threadobj mode bits */
#define __THREAD_M_LOCK        (1 << 0) /* Toggle scheduler lock. */
#define __THREAD_M_WARNSW    (1 << 1) /* Toggle switch warning bit. */
#define __THREAD_M_CONFORMING    (1 << 2) /* Switch to conforming mode. */
#define __THREAD_M_SPARE0    (1 << 16)
#define __THREAD_M_SPARE1    (1 << 17)
#define __THREAD_M_SPARE2    (1 << 18)
#define __THREAD_M_SPARE3    (1 << 19)
#define __THREAD_M_SPARE4    (1 << 20)
#define __THREAD_M_SPARE5    (1 << 21)
#define __THREAD_M_SPARE6    (1 << 22)
#define __THREAD_M_SPARE7    (1 << 23)
 
/*
 * We need to use a valid address here. The object will never be dereferenced
 * when it is identified as IRQ context, so the pthread key itself is fine.
 */
#define THREADOBJ_IRQCONTEXT    ((struct threadobj *)&threadobj_tskey)
 
struct traceobj;
struct syncobj;
 
struct threadobj {
   unsigned int magic;    /* Must be first. */
   pthread_t ptid;
   pthread_mutex_t lock;
 
   int schedlock_depth;
   int cancel_state;
   int status;
   int run_state;
   int policy;
   struct sched_param_ex schedparam;
   int global_priority;
   pid_t cnode;
   pid_t pid;
   char name[32];
 
   void (*finalizer)(struct threadobj *thobj);
   int core_offset;
   int *errno_pointer;
   /* Those members belong exclusively to the syncobj code. */
   struct syncobj *wait_sobj;
   struct holder wait_link;
   int wait_status;
   int wait_prio;
      dref_type(void *) wait_union;
   size_t wait_size;
   timer_t periodic_timer;
 
   struct threadobj_corespec core;
   struct timespec tslice;
   pthread_cond_t barrier;
   struct traceobj *tracer;
   sem_t *cancel_sem;
   struct sysgroup_memspec memspec;
   struct backtrace_data btd;
};
 
struct threadobj_init_data {
   unsigned int magic;
   cpu_set_t affinity;
   int policy;
   struct sched_param_ex param_ex;
   void (*finalizer)(struct threadobj *thobj);
};
 
extern int threadobj_high_prio;
 
extern int threadobj_irq_prio;
 
extern pthread_key_t threadobj_tskey;
 
#ifdef HAVE_TLS
 
extern __thread __attribute__ ((tls_model (CONFIG_XENO_TLS_MODEL)))
struct threadobj *__threadobj_current;
 
static inline void threadobj_set_current(struct threadobj *thobj)
{
   __threadobj_current = thobj;
   pthread_setspecific(threadobj_tskey, thobj);
}
 
static inline struct threadobj *__threadobj_get_current(void)
{
   return __threadobj_current;
}
 
#else /* !HAVE_TLS */
 
static inline void threadobj_set_current(struct threadobj *thobj)
{
   pthread_setspecific(threadobj_tskey, thobj);
}
 
static inline struct threadobj *__threadobj_get_current(void)
{
   return (struct threadobj *)pthread_getspecific(threadobj_tskey);
}
 
#endif /* !HAVE_TLS */
 
static inline struct threadobj *threadobj_current(void)
{
   struct threadobj *thobj = __threadobj_get_current();
   return thobj == NULL || thobj == THREADOBJ_IRQCONTEXT ? NULL : thobj;
}
 
#ifdef CONFIG_XENO_DEBUG
 
static inline void __threadobj_tag_locked(struct threadobj *thobj)
{
   thobj->status |= __THREAD_S_LOCKED;
}
 
static inline void __threadobj_tag_unlocked(struct threadobj *thobj)
{
   assert(thobj->status & __THREAD_S_LOCKED);
   thobj->status &= ~__THREAD_S_LOCKED;
}
 
static inline void __threadobj_check_locked(struct threadobj *thobj)
{
   assert(thobj->status & __THREAD_S_LOCKED);
}
 
#else /* !CONFIG_XENO_DEBUG */
 
static inline void __threadobj_tag_locked(struct threadobj *thobj)
{
}
 
static inline void __threadobj_tag_unlocked(struct threadobj *thobj)
{
}
 
static inline void __threadobj_check_locked(struct threadobj *thobj)
{
}
 
#endif /* !CONFIG_XENO_DEBUG */
 
#ifdef __cplusplus
extern "C" {
#endif
 
void *__threadobj_alloc(size_t tcb_struct_size,
           size_t wait_union_size,
           int thobj_offset);
 
static inline void __threadobj_free(void *p)
{
   xnfree(p);
}
 
static inline void threadobj_free(struct threadobj *thobj)
{
   __threadobj_free((unsigned char *)thobj - thobj->core_offset);
}
 
int threadobj_init(struct threadobj *thobj,
          struct threadobj_init_data *idata) __must_check;
 
int threadobj_start(struct threadobj *thobj) __must_check;
 
int threadobj_shadow(struct threadobj *thobj,
            const char *name);
 
int threadobj_prologue(struct threadobj *thobj,
              const char *name);
 
void threadobj_wait_start(void);
 
void threadobj_notify_entry(void);
 
int threadobj_cancel(struct threadobj *thobj);
 
void threadobj_uninit(struct threadobj *thobj);
 
int threadobj_suspend(struct threadobj *thobj);
 
int threadobj_resume(struct threadobj *thobj);
 
int threadobj_unblock(struct threadobj *thobj);
 
int __threadobj_lock_sched(struct threadobj *current);
 
int threadobj_lock_sched(void);
 
int __threadobj_unlock_sched(struct threadobj *current);
 
int threadobj_unlock_sched(void);
 
int threadobj_set_schedparam(struct threadobj *thobj, int policy,
                const struct sched_param_ex *param_ex);
 
int threadobj_set_schedprio(struct threadobj *thobj, int priority);
 
int threadobj_set_mode(int clrmask, int setmask, int *mode_r);
 
int threadobj_set_periodic(struct threadobj *thobj,
              const struct timespec *__restrict__ idate,
              const struct timespec *__restrict__ period);
 
int threadobj_wait_period(unsigned long *overruns_r) __must_check;
 
void threadobj_spin(ticks_t ns);
 
int threadobj_stat(struct threadobj *thobj,
          struct threadobj_stat *stat);
 
int threadobj_sleep(const struct timespec *ts);
 
void threadobj_set_current_name(const char *name);
 
#ifdef CONFIG_XENO_PSHARED
 
static inline int threadobj_local_p(struct threadobj *thobj)
{
   extern pid_t __node_id;
   return thobj->cnode == __node_id;
}
 
#else /* !CONFIG_XENO_PSHARED */
 
static inline int threadobj_local_p(struct threadobj *thobj)
{
   return 1;
}
 
#endif    /* !CONFIG_XENO_PSHARED */
 
void threadobj_init_key(void);
 
int threadobj_pkg_init(int anon_session);
 
#ifdef __cplusplus
}
#endif
 
#define threadobj_alloc(T, __mptr, W)                    \
   ({                                \
       void *__p;                        \
       __p = __threadobj_alloc(sizeof(T), sizeof(W), offsetof(T, __mptr)); \
       __p;                            \
   })
 
static inline int threadobj_get_policy(struct threadobj *thobj)
{
   return thobj->policy;
}
 
static inline int threadobj_get_priority(struct threadobj *thobj)
{
   return thobj->schedparam.sched_priority;
}
 
static inline void threadobj_copy_schedparam(struct sched_param_ex *param_ex,
                        const struct threadobj *thobj)
{
   *param_ex = thobj->schedparam;
}
 
static inline int threadobj_lock(struct threadobj *thobj)
{
   int ret;
 
   ret = write_lock_safe(&thobj->lock, thobj->cancel_state);
   if (ret)
       return ret;
 
   __threadobj_tag_locked(thobj);
 
   return 0;
}
 
static inline int threadobj_trylock(struct threadobj *thobj)
{
   int ret;
 
   ret = write_trylock_safe(&thobj->lock, thobj->cancel_state);
   if (ret)
       return ret;
 
   __threadobj_tag_locked(thobj);
 
   return 0;
}
 
static inline int threadobj_unlock(struct threadobj *thobj)
{
   __threadobj_check_locked(thobj);
   __threadobj_tag_unlocked(thobj);
   return write_unlock_safe(&thobj->lock, thobj->cancel_state);
}
 
static inline int threadobj_irq_p(void)
{
   struct threadobj *current = __threadobj_get_current();
   return current == THREADOBJ_IRQCONTEXT;
}
 
static inline int threadobj_current_p(void)
{
   return threadobj_current() != NULL;
}
 
static inline int __threadobj_lock_sched_once(struct threadobj *current)
{
   if (current->schedlock_depth == 0)
       return __threadobj_lock_sched(current);
 
   return -EBUSY;
}
 
static inline int threadobj_lock_sched_once(void)
{
   struct threadobj *current = threadobj_current();
 
   if (current->schedlock_depth == 0)
       return threadobj_lock_sched();
 
   return -EBUSY;
}
 
static inline void threadobj_yield(void)
{
   __RT(sched_yield());
}
 
static inline unsigned int threadobj_get_magic(struct threadobj *thobj)
{
   return thobj->magic;
}
 
static inline void threadobj_set_magic(struct threadobj *thobj,
                      unsigned int magic)
{
   thobj->magic = magic;
}
 
static inline int threadobj_get_lockdepth(struct threadobj *thobj)
{
   return thobj->schedlock_depth;
}
 
static inline int threadobj_get_status(struct threadobj *thobj)
{
   return thobj->status | thobj->run_state;
}
 
static inline int threadobj_get_errno(struct threadobj *thobj)
{
   return *thobj->errno_pointer;
}
 
#define threadobj_prepare_wait(T)                    \
   ({                                \
       struct threadobj *__thobj = threadobj_current();    \
       assert(__thobj != NULL);                \
       assert(sizeof(typeof(T)) <= __thobj->wait_size);    \
       __mptr(__thobj->wait_union);                \
   })
 
#define threadobj_finish_wait()        do { } while (0)
 
static inline void *threadobj_get_wait(struct threadobj *thobj)
{
   return __mptr(thobj->wait_union);
}
 
static inline const char *threadobj_get_name(struct threadobj *thobj)
{
   return thobj->name;
}
 
static inline pid_t threadobj_get_pid(struct threadobj *thobj)
{
   return thobj->pid;
}
 
#ifdef CONFIG_XENO_WORKAROUND_CONDVAR_PI
 
int threadobj_cond_timedwait(pthread_cond_t *cond,
                pthread_mutex_t *lock,
                const struct timespec *timeout);
 
int threadobj_cond_wait(pthread_cond_t *cond,
           pthread_mutex_t *lock);
 
int threadobj_cond_signal(pthread_cond_t *cond);
 
int threadobj_cond_broadcast(pthread_cond_t *cond);
 
#else
 
static inline
int threadobj_cond_timedwait(pthread_cond_t *cond,
                pthread_mutex_t *lock,
                const struct timespec *timeout)
{
   return __RT(pthread_cond_timedwait(cond, lock, timeout));
}
 
static inline
int threadobj_cond_wait(pthread_cond_t *cond,
           pthread_mutex_t *lock)
{
   return __RT(pthread_cond_wait(cond, lock));
}
 
static inline
int threadobj_cond_signal(pthread_cond_t *cond)
{
   return __RT(pthread_cond_signal(cond));
}
 
static inline
int threadobj_cond_broadcast(pthread_cond_t *cond)
{
   return __RT(pthread_cond_broadcast(cond));
}
 
#endif /* !CONFIG_XENO_WORKAROUND_CONDVAR_PI */
 
#endif /* _COPPERPLATE_THREADOBJ_H */