diff options
Diffstat (limited to 'firmware/kernel/include')
-rw-r--r-- | firmware/kernel/include/corelock.h | 53 | ||||
-rw-r--r-- | firmware/kernel/include/kernel.h | 69 | ||||
-rw-r--r-- | firmware/kernel/include/mutex.h | 62 | ||||
-rw-r--r-- | firmware/kernel/include/queue.h | 157 | ||||
-rw-r--r-- | firmware/kernel/include/semaphore.h | 40 | ||||
-rw-r--r-- | firmware/kernel/include/thread.h | 387 | ||||
-rw-r--r-- | firmware/kernel/include/tick.h | 67 | ||||
-rw-r--r-- | firmware/kernel/include/timeout.h | 46 |
8 files changed, 881 insertions, 0 deletions
diff --git a/firmware/kernel/include/corelock.h b/firmware/kernel/include/corelock.h new file mode 100644 index 0000000000..79302e0e3c --- /dev/null +++ b/firmware/kernel/include/corelock.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Ulf Ralberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | |||
23 | #ifndef CORELOCK_H | ||
24 | #define CORELOCK_H | ||
25 | |||
26 | #include "config.h" | ||
27 | |||
28 | #ifndef HAVE_CORELOCK_OBJECT | ||
29 | |||
30 | /* No atomic corelock op needed or just none defined */ | ||
31 | #define corelock_init(cl) | ||
32 | #define corelock_lock(cl) | ||
33 | #define corelock_try_lock(cl) | ||
34 | #define corelock_unlock(cl) | ||
35 | |||
36 | #else | ||
37 | |||
38 | /* No reliable atomic instruction available - use Peterson's algorithm */ | ||
39 | struct corelock | ||
40 | { | ||
41 | volatile unsigned char myl[NUM_CORES]; | ||
42 | volatile unsigned char turn; | ||
43 | } __attribute__((packed)); | ||
44 | |||
45 | /* Too big to inline everywhere */ | ||
46 | extern void corelock_init(struct corelock *cl); | ||
47 | extern void corelock_lock(struct corelock *cl); | ||
48 | extern int corelock_try_lock(struct corelock *cl); | ||
49 | extern void corelock_unlock(struct corelock *cl); | ||
50 | |||
51 | #endif /* HAVE_CORELOCK_OBJECT */ | ||
52 | |||
53 | #endif /* CORELOCK_H */ | ||
diff --git a/firmware/kernel/include/kernel.h b/firmware/kernel/include/kernel.h new file mode 100644 index 0000000000..fafff25ce4 --- /dev/null +++ b/firmware/kernel/include/kernel.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Björn Stenberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef KERNEL_H | ||
22 | #define KERNEL_H | ||
23 | |||
24 | #include "config.h" | ||
25 | |||
26 | #include "system.h" | ||
27 | #include "queue.h" | ||
28 | #include "mutex.h" | ||
29 | #include "tick.h" | ||
30 | |||
31 | #ifdef INCLUDE_TIMEOUT_API | ||
32 | #include "timeout.h" | ||
33 | #endif | ||
34 | |||
35 | #ifdef HAVE_SEMAPHORE_OBJECTS | ||
36 | #include "semaphore.h" | ||
37 | #endif | ||
38 | |||
39 | #ifdef HAVE_CORELOCK_OBJECT | ||
40 | #include "corelock.h" | ||
41 | #endif | ||
42 | |||
43 | #define OBJ_WAIT_TIMEDOUT (-1) | ||
44 | #define OBJ_WAIT_FAILED 0 | ||
45 | #define OBJ_WAIT_SUCCEEDED 1 | ||
46 | |||
47 | #define TIMEOUT_BLOCK -1 | ||
48 | #define TIMEOUT_NOBLOCK 0 | ||
49 | |||
50 | static inline void kernel_init(void) | ||
51 | { | ||
52 | /* Init the threading API */ | ||
53 | init_threads(); | ||
54 | |||
55 | /* Other processors will not reach this point in a multicore build. | ||
56 | * In a single-core build with multiple cores they fall-through and | ||
57 | * sleep in cop_main without returning. */ | ||
58 | if (CURRENT_CORE == CPU) | ||
59 | { | ||
60 | init_queues(); | ||
61 | init_tick(); | ||
62 | #ifdef KDEV_INIT | ||
63 | kernel_device_init(); | ||
64 | #endif | ||
65 | } | ||
66 | } | ||
67 | |||
68 | |||
69 | #endif /* KERNEL_H */ | ||
diff --git a/firmware/kernel/include/mutex.h b/firmware/kernel/include/mutex.h new file mode 100644 index 0000000000..bcf5701bd9 --- /dev/null +++ b/firmware/kernel/include/mutex.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Björn Stenberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef MUTEX_H | ||
23 | #define MUTEX_H | ||
24 | |||
25 | #include <stdbool.h> | ||
26 | #include "config.h" | ||
27 | #include "thread.h" | ||
28 | |||
29 | struct mutex | ||
30 | { | ||
31 | struct thread_entry *queue; /* waiter list */ | ||
32 | int recursion; /* lock owner recursion count */ | ||
33 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
34 | struct blocker blocker; /* priority inheritance info | ||
35 | for waiters */ | ||
36 | bool no_preempt; /* don't allow higher-priority thread | ||
37 | to be scheduled even if woken */ | ||
38 | #else | ||
39 | struct thread_entry *thread; /* Indicates owner thread - an owner | ||
40 | implies a locked state - same goes | ||
41 | for priority scheduling | ||
42 | (in blocker struct for that) */ | ||
43 | #endif | ||
44 | IF_COP( struct corelock cl; ) /* multiprocessor sync */ | ||
45 | }; | ||
46 | |||
47 | extern void mutex_init(struct mutex *m); | ||
48 | extern void mutex_lock(struct mutex *m); | ||
49 | extern void mutex_unlock(struct mutex *m); | ||
50 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
51 | /* Deprecated temporary function to disable mutex preempting a thread on | ||
52 | * unlock - firmware/drivers/fat.c and a couple places in apps/buffering.c - | ||
53 | * reliance on it is a bug! */ | ||
54 | static inline void mutex_set_preempt(struct mutex *m, bool preempt) | ||
55 | { m->no_preempt = !preempt; } | ||
56 | #else | ||
57 | /* Deprecated but needed for now - firmware/drivers/ata_mmc.c */ | ||
58 | static inline bool mutex_test(const struct mutex *m) | ||
59 | { return m->thread != NULL; } | ||
60 | #endif /* HAVE_PRIORITY_SCHEDULING */ | ||
61 | |||
62 | #endif /* MUTEX_H */ | ||
diff --git a/firmware/kernel/include/queue.h b/firmware/kernel/include/queue.h new file mode 100644 index 0000000000..1b404f8297 --- /dev/null +++ b/firmware/kernel/include/queue.h | |||
@@ -0,0 +1,157 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Björn Stenberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef QUEUE_H | ||
23 | #define QUEUE_H | ||
24 | |||
25 | #include <stdint.h> | ||
26 | #include "config.h" | ||
27 | #include "thread.h" | ||
28 | |||
29 | /* System defined message ID's - |sign bit = 1|class|id| */ | ||
30 | /* Event class list */ | ||
31 | #define SYS_EVENT_CLS_QUEUE 0 | ||
32 | #define SYS_EVENT_CLS_USB 1 | ||
33 | #define SYS_EVENT_CLS_POWER 2 | ||
34 | #define SYS_EVENT_CLS_FILESYS 3 | ||
35 | #define SYS_EVENT_CLS_PLUG 4 | ||
36 | #define SYS_EVENT_CLS_MISC 5 | ||
37 | #define SYS_EVENT_CLS_PRIVATE 7 /* For use inside plugins */ | ||
38 | /* make sure SYS_EVENT_CLS_BITS has enough range */ | ||
39 | |||
40 | /* Bit 31->|S|c...c|i...i| */ | ||
41 | #define SYS_EVENT ((long)(int)(1 << 31)) | ||
42 | #define SYS_EVENT_CLS_BITS (3) | ||
43 | #define SYS_EVENT_CLS_SHIFT (31-SYS_EVENT_CLS_BITS) | ||
44 | #define SYS_EVENT_CLS_MASK (((1l << SYS_EVENT_CLS_BITS)-1) << SYS_EVENT_SHIFT) | ||
45 | #define MAKE_SYS_EVENT(cls, id) (SYS_EVENT | ((long)(cls) << SYS_EVENT_CLS_SHIFT) | (long)(id)) | ||
46 | /* Macros for extracting codes */ | ||
47 | #define SYS_EVENT_CLS(e) (((e) & SYS_EVENT_CLS_MASK) >> SYS_EVENT_SHIFT) | ||
48 | #define SYS_EVENT_ID(e) ((e) & ~(SYS_EVENT|SYS_EVENT_CLS_MASK)) | ||
49 | |||
50 | #define SYS_TIMEOUT MAKE_SYS_EVENT(SYS_EVENT_CLS_QUEUE, 0) | ||
51 | #define SYS_USB_CONNECTED MAKE_SYS_EVENT(SYS_EVENT_CLS_USB, 0) | ||
52 | #define SYS_USB_CONNECTED_ACK MAKE_SYS_EVENT(SYS_EVENT_CLS_USB, 1) | ||
53 | #define SYS_USB_DISCONNECTED MAKE_SYS_EVENT(SYS_EVENT_CLS_USB, 2) | ||
54 | #define SYS_USB_LUN_LOCKED MAKE_SYS_EVENT(SYS_EVENT_CLS_USB, 4) | ||
55 | #define SYS_USB_READ_DATA MAKE_SYS_EVENT(SYS_EVENT_CLS_USB, 5) | ||
56 | #define SYS_USB_WRITE_DATA MAKE_SYS_EVENT(SYS_EVENT_CLS_USB, 6) | ||
57 | #define SYS_POWEROFF MAKE_SYS_EVENT(SYS_EVENT_CLS_POWER, 0) | ||
58 | #define SYS_CHARGER_CONNECTED MAKE_SYS_EVENT(SYS_EVENT_CLS_POWER, 1) | ||
59 | #define SYS_CHARGER_DISCONNECTED MAKE_SYS_EVENT(SYS_EVENT_CLS_POWER, 2) | ||
60 | #define SYS_BATTERY_UPDATE MAKE_SYS_EVENT(SYS_EVENT_CLS_POWER, 3) | ||
61 | #define SYS_FS_CHANGED MAKE_SYS_EVENT(SYS_EVENT_CLS_FILESYS, 0) | ||
62 | #define SYS_HOTSWAP_INSERTED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 0) | ||
63 | #define SYS_HOTSWAP_EXTRACTED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 1) | ||
64 | #define SYS_PHONE_PLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 2) | ||
65 | #define SYS_PHONE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 3) | ||
66 | #define SYS_REMOTE_PLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 4) | ||
67 | #define SYS_REMOTE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 5) | ||
68 | #define SYS_CAR_ADAPTER_RESUME MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 0) | ||
69 | #define SYS_CALL_INCOMING MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 3) | ||
70 | #define SYS_CALL_HUNG_UP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 4) | ||
71 | #define SYS_VOLUME_CHANGED MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 5) | ||
72 | |||
73 | #define IS_SYSEVENT(ev) ((ev & SYS_EVENT) == SYS_EVENT) | ||
74 | |||
75 | #define MAX_NUM_QUEUES 32 | ||
76 | #define QUEUE_LENGTH 16 /* MUST be a power of 2 */ | ||
77 | #define QUEUE_LENGTH_MASK (QUEUE_LENGTH - 1) | ||
78 | |||
79 | struct queue_event | ||
80 | { | ||
81 | long id; | ||
82 | intptr_t data; | ||
83 | }; | ||
84 | |||
85 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | ||
86 | struct queue_sender_list | ||
87 | { | ||
88 | /* If non-NULL, there is a thread waiting for the corresponding event */ | ||
89 | /* Must be statically allocated to put in non-cached ram. */ | ||
90 | struct thread_entry *senders[QUEUE_LENGTH]; /* message->thread map */ | ||
91 | struct thread_entry *list; /* list of senders in map */ | ||
92 | /* Send info for last message dequeued or NULL if replied or not sent */ | ||
93 | struct thread_entry * volatile curr_sender; | ||
94 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
95 | struct blocker blocker; | ||
96 | #endif | ||
97 | }; | ||
98 | #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ | ||
99 | |||
100 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
101 | #define QUEUE_GET_THREAD(q) \ | ||
102 | (((q)->send == NULL) ? NULL : (q)->send->blocker.thread) | ||
103 | #else | ||
104 | /* Queue without priority enabled have no owner provision _at this time_ */ | ||
105 | #define QUEUE_GET_THREAD(q) \ | ||
106 | (NULL) | ||
107 | #endif | ||
108 | |||
109 | struct event_queue | ||
110 | { | ||
111 | struct thread_entry *queue; /* waiter list */ | ||
112 | struct queue_event events[QUEUE_LENGTH]; /* list of events */ | ||
113 | unsigned int volatile read; /* head of queue */ | ||
114 | unsigned int volatile write; /* tail of queue */ | ||
115 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | ||
116 | struct queue_sender_list * volatile send; /* list of threads waiting for | ||
117 | reply to an event */ | ||
118 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
119 | struct blocker *blocker_p; /* priority inheritance info | ||
120 | for sync message senders */ | ||
121 | #endif | ||
122 | #endif | ||
123 | IF_COP( struct corelock cl; ) /* multiprocessor sync */ | ||
124 | }; | ||
125 | |||
126 | extern void queue_init(struct event_queue *q, bool register_queue); | ||
127 | extern void queue_delete(struct event_queue *q); | ||
128 | extern void queue_wait(struct event_queue *q, struct queue_event *ev); | ||
129 | extern void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, | ||
130 | int ticks); | ||
131 | extern void queue_post(struct event_queue *q, long id, intptr_t data); | ||
132 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | ||
133 | extern void queue_enable_queue_send(struct event_queue *q, | ||
134 | struct queue_sender_list *send, | ||
135 | unsigned int owner_id); | ||
136 | extern intptr_t queue_send(struct event_queue *q, long id, intptr_t data); | ||
137 | extern void queue_reply(struct event_queue *q, intptr_t retval); | ||
138 | extern bool queue_in_queue_send(struct event_queue *q); | ||
139 | #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ | ||
140 | extern bool queue_empty(const struct event_queue* q); | ||
141 | extern bool queue_peek(struct event_queue *q, struct queue_event *ev); | ||
142 | |||
143 | #define QPEEK_FILTER_COUNT_MASK (0xffu) /* 0x00=1 filter, 0xff=256 filters */ | ||
144 | #define QPEEK_FILTER_HEAD_ONLY (1u << 8) /* Ignored if no filters */ | ||
145 | #define QPEEK_REMOVE_EVENTS (1u << 9) /* Remove or discard events */ | ||
146 | extern bool queue_peek_ex(struct event_queue *q, | ||
147 | struct queue_event *ev, | ||
148 | unsigned int flags, | ||
149 | const long (*filters)[2]); | ||
150 | |||
151 | extern void queue_clear(struct event_queue* q); | ||
152 | extern void queue_remove_from_head(struct event_queue *q, long id); | ||
153 | extern int queue_count(const struct event_queue *q); | ||
154 | extern int queue_broadcast(long id, intptr_t data); | ||
155 | extern void init_queues(void); | ||
156 | |||
157 | #endif /* QUEUE_H */ | ||
diff --git a/firmware/kernel/include/semaphore.h b/firmware/kernel/include/semaphore.h new file mode 100644 index 0000000000..40e60bb88d --- /dev/null +++ b/firmware/kernel/include/semaphore.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Björn Stenberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef SEMAPHORE_H | ||
23 | #define SEMAPHORE_H | ||
24 | |||
25 | #include "config.h" | ||
26 | #include "thread.h" | ||
27 | |||
28 | struct semaphore | ||
29 | { | ||
30 | struct thread_entry *queue; /* Waiter list */ | ||
31 | int volatile count; /* # of waits remaining before unsignaled */ | ||
32 | int max; /* maximum # of waits to remain signaled */ | ||
33 | IF_COP( struct corelock cl; ) /* multiprocessor sync */ | ||
34 | }; | ||
35 | |||
36 | extern void semaphore_init(struct semaphore *s, int max, int start); | ||
37 | extern int semaphore_wait(struct semaphore *s, int timeout); | ||
38 | extern void semaphore_release(struct semaphore *s); | ||
39 | |||
40 | #endif /* SEMAPHORE_H */ | ||
diff --git a/firmware/kernel/include/thread.h b/firmware/kernel/include/thread.h new file mode 100644 index 0000000000..9cc33b23ae --- /dev/null +++ b/firmware/kernel/include/thread.h | |||
@@ -0,0 +1,387 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Ulf Ralberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef THREAD_H | ||
23 | #define THREAD_H | ||
24 | |||
25 | #include "config.h" | ||
26 | #include <inttypes.h> | ||
27 | #include <stddef.h> | ||
28 | #include <stdbool.h> | ||
29 | #include "gcc_extensions.h" | ||
30 | #include "corelock.h" | ||
31 | |||
32 | /* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works | ||
33 | * by giving high priority threads more CPU time than lower priority threads | ||
34 | * when they need it. Priority is differential such that the priority | ||
35 | * difference between a lower priority runnable thread and the highest priority | ||
36 | * runnable thread determines the amount of aging necessary for the lower | ||
37 | * priority thread to be scheduled in order to prevent starvation. | ||
38 | * | ||
39 | * If software playback codec pcm buffer is going down to critical, codec | ||
40 | * can gradually raise its own priority to override user interface and | ||
41 | * prevent playback skipping. | ||
42 | */ | ||
43 | #define PRIORITY_RESERVED_HIGH 0 /* Reserved */ | ||
44 | #define PRIORITY_RESERVED_LOW 32 /* Reserved */ | ||
45 | #define HIGHEST_PRIORITY 1 /* The highest possible thread priority */ | ||
46 | #define LOWEST_PRIORITY 31 /* The lowest possible thread priority */ | ||
47 | /* Realtime range reserved for threads that will not allow threads of lower | ||
48 | * priority to age and run (future expansion) */ | ||
49 | #define PRIORITY_REALTIME_1 1 | ||
50 | #define PRIORITY_REALTIME_2 2 | ||
51 | #define PRIORITY_REALTIME_3 3 | ||
52 | #define PRIORITY_REALTIME_4 4 | ||
53 | #define PRIORITY_REALTIME 4 /* Lowest realtime range */ | ||
54 | #define PRIORITY_BUFFERING 15 /* Codec buffering thread */ | ||
55 | #define PRIORITY_USER_INTERFACE 16 /* The main thread */ | ||
56 | #define PRIORITY_RECORDING 16 /* Recording thread */ | ||
57 | #define PRIORITY_PLAYBACK 16 /* Variable between this and MAX */ | ||
58 | #define PRIORITY_PLAYBACK_MAX 5 /* Maximum allowable playback priority */ | ||
59 | #define PRIORITY_SYSTEM 18 /* All other firmware threads */ | ||
60 | #define PRIORITY_BACKGROUND 20 /* Normal application threads */ | ||
61 | #define NUM_PRIORITIES 32 | ||
62 | #define PRIORITY_IDLE 32 /* Priority representative of no tasks */ | ||
63 | |||
64 | #define IO_PRIORITY_IMMEDIATE 0 | ||
65 | #define IO_PRIORITY_BACKGROUND 32 | ||
66 | |||
67 | |||
68 | #if CONFIG_CODEC == SWCODEC | ||
69 | # ifdef HAVE_HARDWARE_CLICK | ||
70 | # define BASETHREADS 17 | ||
71 | # else | ||
72 | # define BASETHREADS 16 | ||
73 | # endif | ||
74 | #else | ||
75 | # define BASETHREADS 11 | ||
76 | #endif /* CONFIG_CODE == * */ | ||
77 | |||
78 | #ifndef TARGET_EXTRA_THREADS | ||
79 | #define TARGET_EXTRA_THREADS 0 | ||
80 | #endif | ||
81 | |||
82 | #define MAXTHREADS (BASETHREADS+TARGET_EXTRA_THREADS) | ||
83 | /* | ||
84 | * We need more stack when we run under a host | ||
85 | * maybe more expensive C lib functions? | ||
86 | * | ||
87 | * simulator (possibly) doesn't simulate stack usage anyway but well ... */ | ||
88 | |||
89 | #if defined(HAVE_SDL_THREADS) || defined(__PCTOOL__) | ||
90 | struct regs | ||
91 | { | ||
92 | void *t; /* OS thread */ | ||
93 | void *told; /* Last thread in slot (explained in thead-sdl.c) */ | ||
94 | void *s; /* Semaphore for blocking and wakeup */ | ||
95 | void (*start)(void); /* Start function */ | ||
96 | }; | ||
97 | |||
98 | #define DEFAULT_STACK_SIZE 0x100 /* tiny, ignored anyway */ | ||
99 | #else | ||
100 | #include "asm/thread.h" | ||
101 | #endif /* HAVE_SDL_THREADS */ | ||
102 | |||
103 | /* NOTE: The use of the word "queue" may also refer to a linked list of | ||
104 | threads being maintained that are normally dealt with in FIFO order | ||
105 | and not necessarily kernel event_queue */ | ||
106 | enum | ||
107 | { | ||
108 | /* States without a timeout must be first */ | ||
109 | STATE_KILLED = 0, /* Thread is killed (default) */ | ||
110 | STATE_RUNNING, /* Thread is currently running */ | ||
111 | STATE_BLOCKED, /* Thread is indefinitely blocked on a queue */ | ||
112 | /* These states involve adding the thread to the tmo list */ | ||
113 | STATE_SLEEPING, /* Thread is sleeping with a timeout */ | ||
114 | STATE_BLOCKED_W_TMO, /* Thread is blocked on a queue with a timeout */ | ||
115 | /* Miscellaneous states */ | ||
116 | STATE_FROZEN, /* Thread is suspended and will not run until | ||
117 | thread_thaw is called with its ID */ | ||
118 | THREAD_NUM_STATES, | ||
119 | TIMEOUT_STATE_FIRST = STATE_SLEEPING, | ||
120 | }; | ||
121 | |||
122 | #if NUM_CORES > 1 | ||
123 | /* Pointer value for name field to indicate thread is being killed. Using | ||
124 | * an alternate STATE_* won't work since that would interfere with operation | ||
125 | * while the thread is still running. */ | ||
126 | #define THREAD_DESTRUCT ((const char *)~(intptr_t)0) | ||
127 | #endif | ||
128 | |||
129 | /* Link information for lists thread is in */ | ||
130 | struct thread_entry; /* forward */ | ||
131 | struct thread_list | ||
132 | { | ||
133 | struct thread_entry *prev; /* Previous thread in a list */ | ||
134 | struct thread_entry *next; /* Next thread in a list */ | ||
135 | }; | ||
136 | |||
137 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
138 | struct blocker | ||
139 | { | ||
140 | struct thread_entry * volatile thread; /* thread blocking other threads | ||
141 | (aka. object owner) */ | ||
142 | int priority; /* highest priority waiter */ | ||
143 | struct thread_entry * (*wakeup_protocol)(struct thread_entry *thread); | ||
144 | }; | ||
145 | |||
146 | /* Choices of wakeup protocol */ | ||
147 | |||
148 | /* For transfer of object ownership by one thread to another thread by | ||
149 | * the owning thread itself (mutexes) */ | ||
150 | struct thread_entry * | ||
151 | wakeup_priority_protocol_transfer(struct thread_entry *thread); | ||
152 | |||
153 | /* For release by owner where ownership doesn't change - other threads, | ||
154 | * interrupts, timeouts, etc. (mutex timeout, queues) */ | ||
155 | struct thread_entry * | ||
156 | wakeup_priority_protocol_release(struct thread_entry *thread); | ||
157 | |||
158 | |||
159 | struct priority_distribution | ||
160 | { | ||
161 | uint8_t hist[NUM_PRIORITIES]; /* Histogram: Frequency for each priority */ | ||
162 | uint32_t mask; /* Bitmask of hist entries that are not zero */ | ||
163 | }; | ||
164 | |||
165 | #endif /* HAVE_PRIORITY_SCHEDULING */ | ||
166 | |||
167 | /* Information kept in each thread slot | ||
168 | * members are arranged according to size - largest first - in order | ||
169 | * to ensure both alignment and packing at the same time. | ||
170 | */ | ||
171 | struct thread_entry | ||
172 | { | ||
173 | struct regs context; /* Register context at switch - | ||
174 | _must_ be first member */ | ||
175 | uintptr_t *stack; /* Pointer to top of stack */ | ||
176 | const char *name; /* Thread name */ | ||
177 | long tmo_tick; /* Tick when thread should be woken from | ||
178 | timeout - | ||
179 | states: STATE_SLEEPING/STATE_BLOCKED_W_TMO */ | ||
180 | struct thread_list l; /* Links for blocked/waking/running - | ||
181 | circular linkage in both directions */ | ||
182 | struct thread_list tmo; /* Links for timeout list - | ||
183 | Circular in reverse direction, NULL-terminated in | ||
184 | forward direction - | ||
185 | states: STATE_SLEEPING/STATE_BLOCKED_W_TMO */ | ||
186 | struct thread_entry **bqp; /* Pointer to list variable in kernel | ||
187 | object where thread is blocked - used | ||
188 | for implicit unblock and explicit wake | ||
189 | states: STATE_BLOCKED/STATE_BLOCKED_W_TMO */ | ||
190 | #ifdef HAVE_CORELOCK_OBJECT | ||
191 | struct corelock *obj_cl; /* Object corelock where thead is blocked - | ||
192 | states: STATE_BLOCKED/STATE_BLOCKED_W_TMO */ | ||
193 | struct corelock waiter_cl; /* Corelock for thread_wait */ | ||
194 | struct corelock slot_cl; /* Corelock to lock thread slot */ | ||
195 | unsigned char core; /* The core to which thread belongs */ | ||
196 | #endif | ||
197 | struct thread_entry *queue; /* List of threads waiting for thread to be | ||
198 | removed */ | ||
199 | #ifdef HAVE_WAKEUP_EXT_CB | ||
200 | void (*wakeup_ext_cb)(struct thread_entry *thread); /* Callback that | ||
201 | performs special steps needed when being | ||
202 | forced off of an object's wait queue that | ||
203 | go beyond the standard wait queue removal | ||
204 | and priority disinheritance */ | ||
205 | /* Only enabled when using queue_send for now */ | ||
206 | #endif | ||
207 | #if defined(HAVE_SEMAPHORE_OBJECTS) || \ | ||
208 | defined(HAVE_EXTENDED_MESSAGING_AND_NAME) || \ | ||
209 | NUM_CORES > 1 | ||
210 | volatile intptr_t retval; /* Return value from a blocked operation/ | ||
211 | misc. use */ | ||
212 | #endif | ||
213 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
214 | /* Priority summary of owned objects that support inheritance */ | ||
215 | struct blocker *blocker; /* Pointer to blocker when this thread is blocked | ||
216 | on an object that supports PIP - | ||
217 | states: STATE_BLOCKED/STATE_BLOCKED_W_TMO */ | ||
218 | struct priority_distribution pdist; /* Priority summary of owned objects | ||
219 | that have blocked threads and thread's own | ||
220 | base priority */ | ||
221 | int skip_count; /* Number of times skipped if higher priority | ||
222 | thread was running */ | ||
223 | unsigned char base_priority; /* Base priority (set explicitly during | ||
224 | creation or thread_set_priority) */ | ||
225 | unsigned char priority; /* Scheduled priority (higher of base or | ||
226 | all threads blocked by this one) */ | ||
227 | #endif | ||
228 | uint16_t id; /* Current slot id */ | ||
229 | unsigned short stack_size; /* Size of stack in bytes */ | ||
230 | unsigned char state; /* Thread slot state (STATE_*) */ | ||
231 | #ifdef HAVE_SCHEDULER_BOOSTCTRL | ||
232 | unsigned char cpu_boost; /* CPU frequency boost flag */ | ||
233 | #endif | ||
234 | #ifdef HAVE_IO_PRIORITY | ||
235 | unsigned char io_priority; | ||
236 | #endif | ||
237 | }; | ||
238 | |||
239 | /*** Macros for internal use ***/ | ||
240 | /* Thread ID, 16 bits = |VVVVVVVV|SSSSSSSS| */ | ||
241 | #define THREAD_ID_VERSION_SHIFT 8 | ||
242 | #define THREAD_ID_VERSION_MASK 0xff00 | ||
243 | #define THREAD_ID_SLOT_MASK 0x00ff | ||
244 | #define THREAD_ID_INIT(n) ((1u << THREAD_ID_VERSION_SHIFT) | (n)) | ||
245 | |||
246 | #ifdef HAVE_CORELOCK_OBJECT | ||
247 | /* Operations to be performed just before stopping a thread and starting | ||
248 | a new one if specified before calling switch_thread */ | ||
249 | enum | ||
250 | { | ||
251 | TBOP_CLEAR = 0, /* No operation to do */ | ||
252 | TBOP_UNLOCK_CORELOCK, /* Unlock a corelock variable */ | ||
253 | TBOP_SWITCH_CORE, /* Call the core switch preparation routine */ | ||
254 | }; | ||
255 | |||
256 | struct thread_blk_ops | ||
257 | { | ||
258 | struct corelock *cl_p; /* pointer to corelock */ | ||
259 | unsigned char flags; /* TBOP_* flags */ | ||
260 | }; | ||
261 | #endif /* NUM_CORES > 1 */ | ||
262 | |||
263 | /* Information kept for each core | ||
264 | * Members are arranged for the same reason as in thread_entry | ||
265 | */ | ||
266 | struct core_entry | ||
267 | { | ||
268 | /* "Active" lists - core is constantly active on these and are never | ||
269 | locked and interrupts do not access them */ | ||
270 | struct thread_entry *running; /* threads that are running (RTR) */ | ||
271 | struct thread_entry *timeout; /* threads that are on a timeout before | ||
272 | running again */ | ||
273 | struct thread_entry *block_task; /* Task going off running list */ | ||
274 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
275 | struct priority_distribution rtr; /* Summary of running and ready-to-run | ||
276 | threads */ | ||
277 | #endif | ||
278 | long next_tmo_check; /* soonest time to check tmo threads */ | ||
279 | #ifdef HAVE_CORELOCK_OBJECT | ||
280 | struct thread_blk_ops blk_ops; /* operations to perform when | ||
281 | blocking a thread */ | ||
282 | struct corelock rtr_cl; /* Lock for rtr list */ | ||
283 | #endif /* NUM_CORES */ | ||
284 | }; | ||
285 | |||
286 | extern void yield(void); | ||
287 | extern unsigned sleep(unsigned ticks); | ||
288 | |||
289 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
290 | #define IF_PRIO(...) __VA_ARGS__ | ||
291 | #define IFN_PRIO(...) | ||
292 | #else | ||
293 | #define IF_PRIO(...) | ||
294 | #define IFN_PRIO(...) __VA_ARGS__ | ||
295 | #endif | ||
296 | |||
297 | void core_idle(void); | ||
298 | void core_wake(IF_COP_VOID(unsigned int core)); | ||
299 | |||
300 | /* Initialize the scheduler */ | ||
301 | void init_threads(void) INIT_ATTR; | ||
302 | |||
303 | /* Allocate a thread in the scheduler */ | ||
304 | #define CREATE_THREAD_FROZEN 0x00000001 /* Thread is frozen at create time */ | ||
305 | unsigned int create_thread(void (*function)(void), | ||
306 | void* stack, size_t stack_size, | ||
307 | unsigned flags, const char *name | ||
308 | IF_PRIO(, int priority) | ||
309 | IF_COP(, unsigned int core)); | ||
310 | |||
311 | /* Set and clear the CPU frequency boost flag for the calling thread */ | ||
312 | #ifdef HAVE_SCHEDULER_BOOSTCTRL | ||
313 | void trigger_cpu_boost(void); | ||
314 | void cancel_cpu_boost(void); | ||
315 | #else | ||
316 | #define trigger_cpu_boost() do { } while(0) | ||
317 | #define cancel_cpu_boost() do { } while(0) | ||
318 | #endif | ||
319 | /* Return thread entry from id */ | ||
320 | struct thread_entry *thread_id_entry(unsigned int thread_id); | ||
321 | /* Make a frozed thread runnable (when started with CREATE_THREAD_FROZEN). | ||
322 | * Has no effect on a thread not frozen. */ | ||
323 | void thread_thaw(unsigned int thread_id); | ||
324 | /* Wait for a thread to exit */ | ||
325 | void thread_wait(unsigned int thread_id); | ||
326 | /* Exit the current thread */ | ||
327 | void thread_exit(void) NORETURN_ATTR; | ||
328 | #if defined(DEBUG) || defined(ROCKBOX_HAS_LOGF) | ||
329 | #define ALLOW_REMOVE_THREAD | ||
330 | /* Remove a thread from the scheduler */ | ||
331 | void remove_thread(unsigned int thread_id); | ||
332 | #endif | ||
333 | |||
334 | /* Switch to next runnable thread */ | ||
335 | void switch_thread(void); | ||
336 | /* Blocks a thread for at least the specified number of ticks (0 = wait until | ||
337 | * next tick) */ | ||
338 | void sleep_thread(int ticks); | ||
339 | /* Indefinitely blocks the current thread on a thread queue */ | ||
340 | void block_thread(struct thread_entry *current); | ||
341 | /* Blocks the current thread on a thread queue until explicitely woken or | ||
342 | * the timeout is reached */ | ||
343 | void block_thread_w_tmo(struct thread_entry *current, int timeout); | ||
344 | |||
345 | /* Return bit flags for thread wakeup */ | ||
346 | #define THREAD_NONE 0x0 /* No thread woken up (exclusive) */ | ||
347 | #define THREAD_OK 0x1 /* A thread was woken up */ | ||
348 | #define THREAD_SWITCH 0x2 /* Task switch recommended (one or more of | ||
349 | higher priority than current were woken) */ | ||
350 | |||
351 | /* A convenience function for waking an entire queue of threads. */ | ||
352 | unsigned int thread_queue_wake(struct thread_entry **list); | ||
353 | |||
354 | /* Wakeup a thread at the head of a list */ | ||
355 | unsigned int wakeup_thread(struct thread_entry **list); | ||
356 | |||
357 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
358 | int thread_set_priority(unsigned int thread_id, int priority); | ||
359 | int thread_get_priority(unsigned int thread_id); | ||
360 | #endif /* HAVE_PRIORITY_SCHEDULING */ | ||
361 | #ifdef HAVE_IO_PRIORITY | ||
362 | void thread_set_io_priority(unsigned int thread_id, int io_priority); | ||
363 | int thread_get_io_priority(unsigned int thread_id); | ||
364 | #endif /* HAVE_IO_PRIORITY */ | ||
365 | #if NUM_CORES > 1 | ||
366 | unsigned int switch_core(unsigned int new_core); | ||
367 | #endif | ||
368 | |||
369 | /* Return the id of the calling thread. */ | ||
370 | unsigned int thread_self(void); | ||
371 | |||
372 | /* Return the thread_entry for the calling thread. | ||
373 | * INTERNAL: Intended for use by kernel and not for programs. */ | ||
374 | struct thread_entry* thread_self_entry(void); | ||
375 | |||
376 | /* Debugging info - only! */ | ||
377 | int thread_stack_usage(const struct thread_entry *thread); | ||
378 | #if NUM_CORES > 1 | ||
379 | int idle_stack_usage(unsigned int core); | ||
380 | #endif | ||
381 | void thread_get_name(char *buffer, int size, | ||
382 | struct thread_entry *thread); | ||
383 | #ifdef RB_PROFILE | ||
384 | void profile_thread(void); | ||
385 | #endif | ||
386 | |||
387 | #endif /* THREAD_H */ | ||
diff --git a/firmware/kernel/include/tick.h b/firmware/kernel/include/tick.h new file mode 100644 index 0000000000..9810f4a1e5 --- /dev/null +++ b/firmware/kernel/include/tick.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Björn Stenberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef TICK_H | ||
22 | #define TICK_H | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "system.h" /* for NULL */ | ||
26 | extern void init_tick(void); | ||
27 | |||
28 | #define HZ 100 /* number of ticks per second */ | ||
29 | |||
30 | #define MAX_NUM_TICK_TASKS 8 | ||
31 | |||
32 | /* global tick variable */ | ||
33 | #if defined(CPU_PP) && defined(BOOTLOADER) && \ | ||
34 | !defined(HAVE_BOOTLOADER_USB_MODE) | ||
35 | /* We don't enable interrupts in the PP bootloader unless USB mode is | ||
36 | enabled for it, so we need to fake the current_tick variable */ | ||
37 | #define current_tick (signed)(USEC_TIMER/10000) | ||
38 | |||
39 | static inline void call_tick_tasks(void) | ||
40 | { | ||
41 | } | ||
42 | #else | ||
43 | extern volatile long current_tick; | ||
44 | |||
45 | /* inline helper for implementing target interrupt handler */ | ||
46 | static inline void call_tick_tasks(void) | ||
47 | { | ||
48 | extern void (*tick_funcs[MAX_NUM_TICK_TASKS+1])(void); | ||
49 | void (**p)(void) = tick_funcs; | ||
50 | void (*fn)(void); | ||
51 | |||
52 | current_tick++; | ||
53 | |||
54 | for(fn = *p; fn != NULL; fn = *(++p)) | ||
55 | { | ||
56 | fn(); | ||
57 | } | ||
58 | } | ||
59 | #endif | ||
60 | |||
61 | /* implemented in target tree */ | ||
62 | extern void tick_start(unsigned int interval_in_ms) INIT_ATTR; | ||
63 | |||
64 | extern int tick_add_task(void (*f)(void)); | ||
65 | extern int tick_remove_task(void (*f)(void)); | ||
66 | |||
67 | #endif /* TICK_H */ | ||
diff --git a/firmware/kernel/include/timeout.h b/firmware/kernel/include/timeout.h new file mode 100644 index 0000000000..0b7c52ba4c --- /dev/null +++ b/firmware/kernel/include/timeout.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Björn Stenberg | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef _KERNEL_H_ | ||
22 | #define _KERNEL_H_ | ||
23 | |||
24 | #include "config.h" | ||
25 | |||
26 | struct timeout; | ||
27 | |||
28 | /* timeout callback type | ||
29 | * tmo - pointer to struct timeout associated with event | ||
30 | * return next interval or <= 0 to stop event | ||
31 | */ | ||
32 | #define MAX_NUM_TIMEOUTS 8 | ||
33 | typedef int (* timeout_cb_type)(struct timeout *tmo); | ||
34 | |||
35 | struct timeout | ||
36 | { | ||
37 | timeout_cb_type callback;/* callback - returning false cancels */ | ||
38 | intptr_t data; /* data passed to callback */ | ||
39 | long expires; /* expiration tick */ | ||
40 | }; | ||
41 | |||
42 | void timeout_register(struct timeout *tmo, timeout_cb_type callback, | ||
43 | int ticks, intptr_t data); | ||
44 | void timeout_cancel(struct timeout *tmo); | ||
45 | |||
46 | #endif /* _KERNEL_H_ */ | ||