forked from espressif/arduino-esp32
-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathxos_thread.h
executable file
·1086 lines (931 loc) · 44.7 KB
/
xos_thread.h
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
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/** @file */
// xos_thread.h - XOS Thread API interface and data structures.
// Copyright (c) 2003-2015 Cadence Design Systems, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// NOTE: Do not include this file directly in your application. Including
// xos.h will automatically include this file.
#ifndef __XOS_THREAD_H__
#define __XOS_THREAD_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "xos_types.h"
#include "xos_params.h"
//-----------------------------------------------------------------------------
// Number of thread priority levels.
//-----------------------------------------------------------------------------
#ifndef XOS_NUM_PRIORITY
#error "XOS_NUM_PRIORITY must be defined (in xos_params.h)."
#endif
#if XOS_NUM_PRIORITY > 32
#error "The number of thread priority levels (XOS_NUM_PRIORITY) must be <= 32."
#endif
#define XOS_MAX_PRIORITY (XOS_NUM_PRIORITY)
//-----------------------------------------------------------------------------
// Macro for thread self pointer.
//-----------------------------------------------------------------------------
#define XOS_THREAD_SELF (xos_thread_id())
//-----------------------------------------------------------------------------
///
/// Thread entry function pointer type.
///
//-----------------------------------------------------------------------------
typedef int32_t (XosThreadFunc)(void * arg, int32_t wake_value);
//-----------------------------------------------------------------------------
// Thread switcher function signature.
//-----------------------------------------------------------------------------
typedef struct XosThread XosThread;
typedef int32_t (XosSwitchFunc)(XosThread *);
//-----------------------------------------------------------------------------
///
/// Condition evaluation callback function pointer type.
///
//-----------------------------------------------------------------------------
typedef int32_t (XosCondFunc)(void * arg, int32_t sig_value, XosThread * thread);
//-----------------------------------------------------------------------------
///
/// Thread exit handler function pointer type.
///
//-----------------------------------------------------------------------------
typedef int32_t (XosThdExitFunc)(int32_t exitcode);
//-----------------------------------------------------------------------------
// Thread queue structure. Used to implement the ready queues as well
// as the wait queues.
//-----------------------------------------------------------------------------
typedef struct XosThreadQueue {
XosThread * head; // Pointer to first thread in queue, or 0 if none.
XosThread ** tail; // Pointer to last thread's r_next pointer, or
// to "head" if none.
} XosThreadQueue;
//-----------------------------------------------------------------------------
// Stack frame for a thread that is not running. That is, it has either
// been preempted or has yielded.
//-----------------------------------------------------------------------------
typedef union XosFrame {
XosExcFrame e; // resume_fn == &xos_resume_preempted_thread
XosCoopFrame c; // resume_fn == &xos_resume_cooperative_thread
// nothing for resume_fn == &xos_resume_idle_thread
// nothing for resume_fn == &xos_resume_by_restart
} XosFrame;
//-----------------------------------------------------------------------------
// Thread Control Block. Tracks the state and control information associated
// with a thread.
//
// IMPORTANT: keep this in sync with TCB_*** offsets in xos_common.h .
//-----------------------------------------------------------------------------
struct XosThread {
XosThread * r_next; // 00 Next thread in queue (eg. ready queue of
// its priority, or some queue of blocked threads)
// Should be NULL if not in any queue.
XosThread ** r_pprev; // 04 Points to previous queue entry's r_next
// pointer (i.e. to itself), or to queue head
// if first in queue. NULL if not in any queue.
XosThread * all_next; // 08 Next in list of all threads.
void * resume_fn; // 12 Pointer to the routine to be called to
// resume this thread. On entry to such code:
// a2 == xos_curr_threadptr (thread being resumed)
// a3 == &xos_globals
XosFrame * esf; // 16 Pointer to saved exception stack frame,
// just below thread's current stack pointer.
// For RTC threads, this is valid only while the
// thread is preempted, not when it is blocked.
void * tie_save; // 20 TIE state save area. May be NULL if there
// is not TIE state saved for this thread.
int32_t wake_value; // 24 Value returned from block call (by wake call)
// (for RTC: pass this to start function??)
XosSwitchFunc * switch_fn; // 28 Pointer to a function that
// can be called from within this thread, to save
// this thread's state and switch to a specified
// other thread. Returns wake value.
void * stack_base; // 32 Base of stack as specified by thread creator.
void * stack_end; // 36 End of stack (adjusted for TIE state save area
// if any).
XosThreadFunc * entry; // 40 Pointer to thread entry function. Used for
// RTC thread restart.
void * arg; // 44 Argument value passed to entry function.
bool ready; // 48 Set when thread is ready to run, and is in
// its priority queue (i.e. r_pprev is set when
// this flag is set).
bool in_exit; // Exit flag, nonzero when in exit processing.
int8_t priority; // Thread priority, 0 .. (XOS_MAX_PRI - 1). Higher
// numbers have higher priority. This must only be
// changed when thread is not ready, or by calling
// xos_thread_set_priority().
int8_t preempt_pri; // This thread's preemption blocking priority.
// (preempt_pri >= priority). A thread's priority
// must be higher than another's preempt_pri to be
// able to preempt it. Note that preempt_pri can
// change during runtime e.g. due to priority
// inheritance.
uint32_t flags; // 52 Thread creation flags.
const char * name; // 56 Thread name (mainly for debug).
const char * block_cause; // 60 Reason for blocking. Valid only when thread
// not ready (r_pprev == 0).
XosThread * container; // 64 Thread whose stack will be used to run
// this thread. Valid for RTC threads only, else NULL.
XosThdExitFunc * exit_func; // 68 Thread exit handler function pointer.
XosThreadQueue exit_waiters; // 72 Queue of threads waiting for this one to exit.
XosThreadQueue * wq_ptr; // 80 If this thread is in a wait queue, this
// points to the queue. Must be NULL when
// thread not in a queue.
XosCondFunc * cond_fn; // 84 Condition function. Valid only while thread
// is blocked on condition.
void * cond_arg; // 88 Argument to be passed to condition function.
uint16_t cp_mask; // 92 Mask of coprocessors used.
uint16_t cp_saved; // 94 Mask of coprocessors saved.
uint32_t event_bits; // 96 event bits
uint32_t event_mask; // 100 event bit mask
uint32_t event_flags; // 104 event flags
void * clib_ptr; // 108 Pointer to C lib context struct.
uint32_t sig; // 112 Signature of valid TCB
uint32_t resume_ccount; // 116 cycle count at resume
uint64_t cycle_count; // 120 number of cycles consumed (approx).
// NOTE: must be 8-byte aligned
uint32_t normal_resumes; // 128 Number of non-preemptive resumptions.
uint32_t preempt_resumes;// 132 Number of preemptive resumptions.
#if XOS_OPT_THREAD_SAFE_CLIB
CLIB_THREAD_STRUCT; // C library context area.
#endif
};
//-----------------------------------------------------------------------------
// User-visible flags for xos_thread_create().
//-----------------------------------------------------------------------------
#define XOS_THREAD_SUSPEND 0x0001 ///< Create suspended instead of ready
#define XOS_THREAD_RTC 0x0002 ///< Run-to-completion thread
#define XOS_THREAD_NO_CP 0x0004 ///< Thread does not use coprocessors
//-----------------------------------------------------------------------------
// Flags used by thread creation extra parameters.
//-----------------------------------------------------------------------------
#define XOS_TP_COPROC_MASK 0x0001
#define XOS_TP_PREEMPT_PRI 0x0002
#define XOS_TP_EXIT_HANDLER 0x0004
//-----------------------------------------------------------------------------
// Thread creation extra parameters.
//-----------------------------------------------------------------------------
typedef struct XosThreadParm {
uint32_t parms_mask; // Combination of XOS_TP_xxx flags indicating
// which parameters are valid.
uint16_t cp_mask; // Mask of coprocessors the thread can access.
uint32_t preempt_pri; // Initial preemption blocking priority. Can be
// changed later via xos_thread_set_priority().
XosThdExitFunc * handler; // Exit handler function.
} XosThreadParm;
//-----------------------------------------------------------------------------
// Wrapper struct for RTC (run to completion) thread.
//-----------------------------------------------------------------------------
typedef struct XosRtcThread {
struct XosThread thread;
} XosRtcThread;
//-----------------------------------------------------------------------------
// External variables.
//-----------------------------------------------------------------------------
extern XosThread * xos_curr_threadptr; // Current active thread
extern XosThread * xos_next_threadptr; // Next ready thread
extern XosThread * xos_all_threads; // List of all threads
//-----------------------------------------------------------------------------
///
/// Set thread creation parameter: the group of coprocessors that this thread
/// will use. This must be set during thread creation, and cannot be changed
/// after the thread has been created. Defining this allows reduction of
/// memory usage (for CP state saving) in some circumstances, and can also
/// speed up the context switch time.
///
/// NOTE: Support for this is not currently implemented. If a thread uses
/// any coprocessor, space for all coprocessors must be reserved.
///
/// \param parms Thread creation parameter structure. Must be
/// allocated by the caller.
///
/// \param cp_mask Bitmask of coprocessors thread is allowed to
/// use. Bit 0 for coprocessor 0, etc.
///
/// \return Returns nothing.
///
//-----------------------------------------------------------------------------
static inline void
xos_threadp_set_cp_mask(XosThreadParm * parms, uint16_t cp_mask)
{
if (parms != XOS_NULL) {
parms->parms_mask |= XOS_TP_COPROC_MASK;
parms->cp_mask = cp_mask;
}
}
//-----------------------------------------------------------------------------
///
/// Set thread creation parameter: thread pre-emption priority.
///
/// \param parms Thread creation parameter structure. Must be
/// allocated by caller.
///
/// \param preempt_pri Thread pre-emption blocking priority.
/// From 0 .. XOS_NUM_PRIORITY - 1.
/// Must be greater or equal to the thread priority
/// (if not, is automatically set to thread priority).
///
/// \return Returns nothing.
///
//-----------------------------------------------------------------------------
static inline void
xos_threadp_set_preemption_priority(XosThreadParm * parms, int8_t preempt_pri)
{
if (parms != XOS_NULL) {
parms->parms_mask |= XOS_TP_PREEMPT_PRI;
parms->preempt_pri = preempt_pri;
}
}
//-----------------------------------------------------------------------------
///
/// Set thread creation parameter: thread exit handler.
///
/// \param parms Thread creation parameter structure. Must be
/// allocated by caller.
///
/// \param handler Exit handler function.
///
/// \return Returns nothing.
//-----------------------------------------------------------------------------
static inline void
xos_threadp_set_exit_handler(XosThreadParm * parms, XosThdExitFunc * handler)
{
if (parms != XOS_NULL) {
parms->parms_mask |= XOS_TP_EXIT_HANDLER;
parms->handler = handler;
}
}
//-----------------------------------------------------------------------------
///
/// Create a new thread. If the thread is not created suspended, then it will
/// be made ready as soon as it is created, and will immediately run if it is
/// the highest priority non-blocked thread in the system.
///
/// \param thread Pointer to the thread descriptor (an otherwise
/// unused XosThread structure, usually allocated
/// by the caller for the lifetime of the thread,
/// for example as a global variable).
///
/// \param container Pointer to separate thread acting as "container"
/// for this one. At the moment, this is only meaningful
/// for run-to-completion (RTC) threads (identified with
/// the XOS_THREAD_RTC flag), in which case the container
/// must have the same priority and also be an RTC thread.
/// (The priority restriction may be lifted in a future
/// implementation, with appropriate constraints on dynamic
/// reprioritization of the created thread).
///
/// \param entry Thread entry function, takes one argument.
///
/// \param arg Argument "void*" that is passed to the thread function.
///
/// \param name Unique name of the thread, for debug/display purposes.
/// This string must be valid for the lifetime of the thread
/// (only a pointer to it is stored in the thread control block).
/// Typically consists of identifier chars with no spaces.
///
/// \param stack Base of initial stack for the thread, allocated by the
/// caller. Need not be aligned (initial stack pointer will be
/// computed and aligned from given stack base and size).
/// Required argument, except for run-to-completion threads
/// when container is non-NULL, in which case the container's
/// stack is used and this argument must be NULL.
///
/// \param stack_size Size of the stack, in bytes.
/// NOTE: stack should be at least XOS_STACK_EXTRA bytes plus
/// whatever the thread actually needs if the thread will use
/// coprocessors/TIE state. If the thread will not touch the
/// coprocessors, then it should be XOS_STACK_EXTRA_NO_CP
/// plus whatever the thread actually needs.
/// Recommended minimum stack sizes are defined by the constants
/// XOS_STACK_MIN_SIZE and XOS_STACK_MIN_SIZE_NO_CP.
///
/// For run-to-completion threads where container is non-NULL,
/// stack_size specifies the minimum stack size required for
/// the thread; it should be smaller or equal to the container's
/// stack.
///
/// \param priority Initial thread priority. From 0 .. XOS_MAX_PRI - 1.
/// Higher numbers are higher priority.
///
/// \param parms Pointer to extra parameters structure, or 0 if none given.
/// Use xos_thread_p_***() functions to set parameters in the
/// structure.
///
/// \param flags Option flags:
/// - XOS_THREAD_SUSPEND -- Leave thread suspended instead of
/// making it ready. The thread can be made ready to run later
/// by calling xos_thread_resume().
/// - XOS_THREAD_RTC -- Run-to-completion thread.
/// - XOS_THREAD_NO_CP -- Thread does not use coprocessors.
/// No coprocessor state will be saved for this thread.
/// Threads that have this flag set will not allocate any
/// storage for saving coprocessor state and so can have
/// smaller stacks.
///
/// NOTE: xos_start_main() calls xos_thread_create() to convert main() into the 'main'
/// thread.
///
/// \return Returns XOS_OK if successful, error code otherwise.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_create(XosThread * thread,
XosThread * container,
XosThreadFunc * entry,
void * arg,
const char * name,
void * stack,
uint32_t stack_size,
int32_t priority,
XosThreadParm * parms,
uint32_t flags );
//-----------------------------------------------------------------------------
///
/// Remove thread and free up all resources. Thread must have exited already.
/// After this call returns, all resources allocated to the thread (e.g. TCB,
/// stack space, etc.) can be reused.
///
/// \param thread Handle of thread to be deleted.
///
/// \return Returns XOS_OK on success, else error code.
///
/// NOTE: A thread cannot call this on itself.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_delete(XosThread * thread);
//-----------------------------------------------------------------------------
///
/// Force the thread to terminate. The thread execution is aborted, but exit
/// processing will still happen, i.e. the exit handler (if any) will be run.
/// After termination, any other threads waiting on this thread are notified.
/// This function cannot be called on the current thread.
///
/// \param thread Handle of thread to be aborted.
///
/// \param exitcode Exit code returned to any waiting threads.
///
/// \return Returns XOS_OK on success, else error code.
///
/// NOTE: If the thread is blocked waiting for something, the wait is aborted
/// and the thread is made ready.
/// NOTE: The thread is not guaranteed to have exited when this call returns.
/// It will be made ready and set up for exit processing, but when the exit
/// processing will actually happen depends on the state of the system and
/// the priority of the thread being aborted.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_abort(XosThread * thread, int32_t exitcode);
//-----------------------------------------------------------------------------
///
/// Exit the current thread. The exit handler (if any) will be run before the
/// thread terminates.
///
/// \param exitcode Exit code to be returned to any waiting threads.
///
/// \return This function does not return.
///
/// NOTE: This is automatically called if the thread returns from its entry
/// function. The entry function's return value will be passed as the exit
/// code.
///
//-----------------------------------------------------------------------------
void
xos_thread_exit(int32_t exitcode);
//-----------------------------------------------------------------------------
///
/// Wait until the specified thread exits and get its exit code. If the thread
/// has exited already, an error will be returned.
///
/// \param thread The thread to wait for. Cannot be "self", i.e.
/// one cannot wait on one's own exit.
///
/// \param p_exitcode If not null, the exit code will be returned here.
///
/// \return Returns XOS_OK on sucess, else error code.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_join(XosThread * thread, int32_t * p_exitcode);
//-----------------------------------------------------------------------------
///
/// Yield the CPU to the next thread in line. The calling thread remains ready
/// and is placed at the tail of the ready queue at its current priority level.
/// If there are no threads at the same priority level that are ready to run,
/// then this call will return immediately.
///
/// \return Returns nothing.
///
//-----------------------------------------------------------------------------
void
xos_thread_yield();
//-----------------------------------------------------------------------------
///
/// Suspend the specified thread. The thread will remain suspended until
/// xos_thread_resume() has been called on it. If the thread is already blocked
/// on some other condition, then this function will return an error.
///
/// \param thread Handle of thread being suspended. A thread can
/// use the special handle XOS_THREAD_SELF to suspend
/// itself.
///
/// \return Returns XOS_OK on success, else error code.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_suspend(XosThread * thread);
//-----------------------------------------------------------------------------
///
/// Resume a suspended thread. If the thread is not suspended or is blocked on
/// some other condition then this function will do nothing. Otherwise, it will
/// be made ready, and this can cause an immediate context switch if the thread
/// is at a higher priority than the calling thread.
///
/// \param thread Handle of thread being resumed.
///
/// \return Returns XOS_OK on success, else error code.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_resume(XosThread * thread);
//-----------------------------------------------------------------------------
///
/// Get the priority of the specified thread. This returns the priority of the
/// queried thread at this instant, however this can change at any time due to
/// other activity in the system.
///
/// \param thread Handle of thread being queried. A thread can use
/// the special handle XOS_THREAD_SELF to query itself.
///
/// \return Returns the thread's current priority, or -1 if the thread handle
/// is not valid.
///
//-----------------------------------------------------------------------------
static inline int32_t
xos_thread_get_priority(XosThread * thread)
{
XOS_ASSERT(thread);
return thread ? thread->priority : -1;
}
//-----------------------------------------------------------------------------
///
/// Set the priority of the specified thread. The thread must exist.
///
/// \param thread Handle of thread being affected. A thread can
/// use the special handle XOS_THREAD_SELF to specify
/// itself.
///
/// \param priority The new priority level to be set.
///
/// \return Returns XOS_OK on success, else error code.
///
/// NOTE: Calling this function can result in a scheduler activation, and the
/// caller may be suspended as a result.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_set_priority(XosThread * thread, int32_t priority);
//-----------------------------------------------------------------------------
///
/// Return the name of the specified thread.
///
/// \param thread Handle of thread being queried. A thread can use
/// the special handle XOS_THREAD_SELF to specify
/// itself.
///
/// \return Returns a pointer to the name string if available, else NULL.
///
//-----------------------------------------------------------------------------
static inline const char *
xos_thread_get_name(XosThread * thread)
{
XOS_ASSERT(thread);
return thread ? thread->name : 0;
}
//-----------------------------------------------------------------------------
///
/// Set the name of the specified thread.
///
/// \param thread Handle of thread whose name is to be set. A thread
/// can use the special handle XOS_THREAD_SELF to specify
/// itself.
///
/// \param name Pointer to the new name string. The string is not
/// copied, only the pointer is saved. So the string
/// must be persistent for the life of the thread.
///
/// \return Returns XOS_OK on success, else error code.
///
//-----------------------------------------------------------------------------
static inline int32_t
xos_thread_set_name(XosThread * thread, const char * name)
{
XOS_ASSERT(thread);
if (thread != XOS_NULL) {
thread->name = name;
return XOS_OK;
}
return XOS_ERR_INVALID_PARAMETER;
}
//-----------------------------------------------------------------------------
///
/// Set an exit handler for the specified thread. The exit handler is run when
/// the thread terminates, either by calling xos_thread_exit() or by returning
/// from its entry function. It will also be called if the thread is being
/// terminated due to e.g. an unhandled exception.
///
/// The handler must be a function defined as e.g.:
///
/// int32_t exit_handler(int32_t exitcode);
///
/// The exit handler runs in the context of the exiting thread, and can call
/// system services. It is provided with a single parameter which is the
/// thread's exit code (the exit code may be set to an error code if the
/// thread is being terminated due to an error or exception). The handler
/// must return a value which will be set as the thread's exit code.
///
/// \param thread Handle of the thread for which the handler is
/// to be installed. A thread can use the special
/// handle XOS_THREAD_SELF to specify itself.
///
/// \param func Pointer to exit handler function. To clear an
/// existing handler, pass NULL as the pointer.
///
/// \return Returns XOS_OK on success, else error code.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_set_exit_handler(XosThread * thread, XosThdExitFunc * func);
//-----------------------------------------------------------------------------
///
/// Return the ID (handle) of the current thread.
///
/// \return Returns the handle of the current thread. This handle can be
/// used in all XOS system calls.
///
/// NOTE: If called from interrupt context, returns the handle of the thread
/// that was preempted.
///
//-----------------------------------------------------------------------------
static inline XosThread *
xos_thread_id()
{
return xos_curr_threadptr;
}
//-----------------------------------------------------------------------------
///
/// Return the coprocessor mask for the specified thread.
///
/// \param thread Handle of thread being queried.
///
/// \return Returns the mask for the specified thread if available, else 0.
///
//-----------------------------------------------------------------------------
static inline uint16_t
xos_thread_cp_mask(XosThread * thread)
{
XOS_ASSERT(thread);
return thread ? thread->cp_mask : 0;
}
//-----------------------------------------------------------------------------
///
/// Return the wake value for the specified thread.
///
/// \return thread Handle of thread being queried.
///
/// \return Returns The last set wake value. There is no way to detect what
/// action set the wake value and when.
///
//-----------------------------------------------------------------------------
static inline int32_t
xos_thread_get_wake_value(XosThread * thread)
{
XOS_ASSERT(thread);
return thread ? thread->wake_value : 0;
}
//-----------------------------------------------------------------------------
///
/// Return the current value of the event bits for the current thread.
/// This function takes no parameters.
///
/// \return Returns the current value of the event bits. The event bits
/// are set when the thread is woken from an event wait. They will
/// not change while the thread is running. There is no way to
/// determine when the event bits were last updated.
///
//-----------------------------------------------------------------------------
static inline uint32_t
xos_thread_get_event_bits(void)
{
XosThread * thread = xos_thread_id();
return thread ? thread->event_bits : 0;
}
//-----------------------------------------------------------------------------
///
/// Enum values for thread state.
///
//-----------------------------------------------------------------------------
typedef enum xos_thread_state_t {
XOS_THREAD_STATE_INVALID = 0, ///< Invalid thread
XOS_THREAD_STATE_BLOCKED, ///< Thread is blocked
XOS_THREAD_STATE_READY, ///< Thread is ready to run
XOS_THREAD_STATE_RUNNING, ///< Thread is running
XOS_THREAD_STATE_EXITED, ///< Thread has exited
} xos_thread_state_t;
//-----------------------------------------------------------------------------
///
/// Return the state of the specified thread.
///
/// \param thread Handle of thread being queried.
///
/// \return Returns one of the following values:
/// - XOS_THREAD_STATE_RUNNING -- The thread is currently running.
/// - XOS_THREAD_STATE_READY -- The thread is ready to run.
/// - XOS_THREAD_STATE_BLOCKED -- The thread is blocked on something.
/// - XOS_THREAD_STATE_INVALID -- The thread handle is invalid.
/// - XOS_THREAD_STATE_EXITED -- The thread has exited.
///
//-----------------------------------------------------------------------------
xos_thread_state_t
xos_thread_get_state(XosThread * thread);
//-----------------------------------------------------------------------------
///
/// Disable thread preemption. Prevents context switching to another thread.
/// However, interrupt handlers will still continue to be run. Multiple calls
/// will nest, and the same number of calls to xos_preemption_enable() will be
/// required to re-enable preemption. If the calling thread yields the CPU or
/// exits without enabling preemption, it will cause a system halt.
/// If the calling thread encounters a fatal error, preemption will be enabled
/// during fatal error handling.
///
/// \return Returns the new value of preemption disable flag after this call.
///
/// NOTE: Cannot be called from interrupt context.
///
//-----------------------------------------------------------------------------
uint32_t
xos_preemption_disable(void);
//-----------------------------------------------------------------------------
///
/// Enable thread preemption. Has no effect if preemption was already enabled.
/// Otherwise, it decrements the value of the preemption disable flag and if
/// the value goes to zero, enables preemption.
///
/// \return Returns the new value of preemption disable flag after this call.
///
/// NOTE: If scheduling gets enabled, it may cause an immediate context switch
/// if higher priority threads are ready.
///
//-----------------------------------------------------------------------------
uint32_t
xos_preemption_enable(void);
//-----------------------------------------------------------------------------
///
/// Initialize XOS thread support and start scheduler.
///
/// Must be called from main() before calling any other thread function.
/// This function initializes thread support, creates the idle thread, and
/// starts the scheduler. It does not return to its caller. This means that
/// at least one user thread must be created before calling xos_start().
/// Otherwise, the scheduler will run the idle thread since it will be the
/// only thread in the system, and no other thread can be created.
///
/// NOTE: This function does not initialize timer/tick support. For timer
/// services to be available xos_start_system_timer() must be called.
///
/// NOTE: xos_start() and xos_start_main() are exclusive, both cannot be
/// called within the same application.
///
/// \param flags Currently unused (pass 0).
///
/// \return Does not return.
///
//-----------------------------------------------------------------------------
void
xos_start(uint32_t flags);
//-----------------------------------------------------------------------------
///
/// Initialize XOS thread support and create init (main) thread.
///
/// Must be called from main() before calling any other thread function.
/// This function converts the caller into the 'main' or 'init' thread, and
/// returns to the caller after completing initialization.
///
/// NOTE: This function does not initialize timer/tick support. For timer
/// services to be available xos_start_system_timer() must be called.
///
/// NOTE: xos_start_main() and xos_start() are exclusive, both cannot be
/// called within the same application.
///
/// \param name Name of main thread (see xos_thread_create()).
///
/// \param priority Initial priority of main thread.
///
/// \param flags Currently unused (pass 0).
///
/// \return Returns nothing.
///
//-----------------------------------------------------------------------------
void
xos_start_main(const char * name, int8_t priority, uint32_t flags);
//-----------------------------------------------------------------------------
///
/// Per-thread stats structure.
/// Note that the CPU use % is approximate, both because of cycle counting
/// and because of integer division. So all the threads' CPU % will not add
/// up to exactly 100%.
///
//-----------------------------------------------------------------------------
typedef struct XosThreadStats {
XosThread * thread; ///< Thread handle (or pseudo-handle)
uint32_t cpu_pct; ///< CPU use % for this thread
uint32_t normal_switches; ///< Number of non-preemptive switches.
uint32_t preempt_switches; ///< Number of preemptive switches.
uint64_t cycle_count; ///< Number of cycles consumed.
} XosThreadStats;
//-----------------------------------------------------------------------------
// Thread pseudo-handles.
//-----------------------------------------------------------------------------
#define XOS_THD_STATS_IDLE ((XosThread *) 1)
#define XOS_THD_STATS_INTR ((XosThread *) 2)
//-----------------------------------------------------------------------------
///
/// Get the thread statistics for the specified thread. Statistics are only
/// available if XOS_OPT_STATS has been enabled. Otherwise, the function
/// will return XOS_OK, but the structure contents will be undefined.
///
/// \param thread Handle of thread being queried. The following
/// special pseudo-handles can be used:
/// - XOS_THD_STATS_IDLE -- stats for idle thread
/// - XOS_THD_STATS_INTR -- stats for interrupt processing
///
/// \param stats Pointer to XosThreadStats struct to be filled in.
///
/// \return Returns XOS_OK on success, else error code.
///
/// NOTE: Can be called from interrupt context.
/// NOTE: This call will not fill in the "thread" and "cpu_pct" fields in the
/// "stats" structure. The thread handle is already known, and calculating the
/// CPU loading can take quite a bit of time so is not done here.
///
//-----------------------------------------------------------------------------
int32_t
xos_thread_get_stats(XosThread * thread, XosThreadStats * stats);
//-----------------------------------------------------------------------------
///
/// Get CPU loading statistics for the system. This function computes the CPU
/// percentage use for all threads in the system (including the idle thread and
/// the 'interrupt thread' (interrupt context). It also returns the cycle count
/// and number of context switches for each thread.
/// Statistics are only available if XOS_OPT_STATS has been enabled.
/// Otherwise, the function will return XOS_OK, but the structure contents will
/// be undefined.
///
/// IMPORTANT: The entry for interrupt context does not contain a real thread
/// handle. It uses the pseudo-handle XOS_THD_STATS_INTR to indicate that this
/// entry reports interrupt statistics. This pseudo-handle cannot be used for
/// any other thread operations or queries.
///
/// NOTE: This function disables interrupts while traversing the thread list.
/// It does not leave interrupts disabled during the computations, as that can
/// take a fair amount of time.
///
/// \param stats Pointer to an array of XosThreadStats structures.
/// The array must be large enough to accommodate all
/// threads in the system.
///
/// \param size The number of elements available in the array. If
/// this is smaller than the number of threads plus one
/// (for the interrupt context) then XOS_ERR_INVALID_PARAMETER
/// will be returned and '*size' will be set to the
/// minimum number of elements required. On a successful
/// return, '*size' is set to the number of elements
/// actually filled in.
///
/// \param reset If nonzero, then thread stats counters are reset
/// after reading. This is useful if you want to track
/// the stats so as to get a better idea of current
/// system loading. E.g. calling this function once a
/// second with 'reset' nonzero will provide CPU load
/// information for the last second on each call.
///
/// \return Returns XOS_OK on success, else error code. In particular,
/// XOS_ERR_INVALID_PARAMETER will be returned if the output buffer
/// is too small.
///
//-----------------------------------------------------------------------------
int32_t
xos_get_cpu_load(XosThreadStats * stats, int32_t * size, int32_t reset);
#ifdef _XOS_INCLUDE_INTERNAL_
// Signature of valid thread object
#define XOS_THREAD_SIG 0x54485244
// Extern functions
void
xos_init(void);
bool
xos_init_done(void);
bool
xos_started(void);
int32_t
xos_schedule(XosThread * curr_thread);
void
xos_q_remove(XosThreadQueue * queue, XosThread * thread);
XosThread *
xos_q_pop(XosThreadQueue * queue);
int32_t
xos_wake_queue(XosThreadQueue * queue, const char * expected_cause, int32_t wake_value);
// Well known block causes
extern const char * const xos_blkon_idle; // (for idle thread only)
extern const char * const xos_blkon_suspend;
extern const char * const xos_blkon_delay;
extern const char * const xos_blkon_exited;