source: mainline/src/proc/thread.c@ c5ae095

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c5ae095 was 9c0a9b3, checked in by Jakub Vana <jakub.vana@…>, 20 years ago

1) memcopy and _memcopy functions rewriten to ANSI C norm.
2) Repaired ia32,ia64 and mips version of SPARTAN to work with this memcopy functions
3) Warning for non declared funcions added and repaired ia32,ia64 and mips versions to pass build process with this warning and Werror option

  • Property mode set to 100644
File size: 7.3 KB
RevLine 
[f761f1eb]1/*
2 * Copyright (C) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <proc/scheduler.h>
30#include <proc/thread.h>
31#include <proc/task.h>
32#include <mm/heap.h>
33#include <mm/frame.h>
34#include <mm/page.h>
35#include <arch/asm.h>
36#include <arch.h>
37#include <synch/synch.h>
38#include <synch/spinlock.h>
39#include <synch/waitq.h>
40#include <synch/rwlock.h>
41#include <cpu.h>
42#include <func.h>
43#include <context.h>
44#include <list.h>
45#include <typedefs.h>
46#include <time/clock.h>
47#include <list.h>
[4ffa9e0]48#include <config.h>
49#include <arch/interrupt.h>
[26a8604f]50#include <smp/ipi.h>
[f2ffad4]51#include <arch/faddr.h>
[e3f41b6]52#include <arch/atomic.h>
[9c0a9b3]53#include <memstr.h>
[f761f1eb]54
[70527f1]55char *thread_states[] = {"Invalid", "Running", "Sleeping", "Ready", "Entering", "Exiting"}; /**< Thread states */
[f761f1eb]56
57spinlock_t threads_lock;
58link_t threads_head;
59
60static spinlock_t tidlock;
61__u32 last_tid = 0;
62
[70527f1]63
64/** Thread wrapper
65 *
66 * This wrapper is provided to ensure that every thread
[f761f1eb]67 * makes a call to thread_exit() when its implementing
68 * function returns.
69 *
[70527f1]70 * cpu_priority_high() is assumed.
71 *
[f761f1eb]72 */
73void cushion(void)
74{
[43114c5]75 void (*f)(void *) = THREAD->thread_code;
76 void *arg = THREAD->thread_arg;
[f761f1eb]77
[cb4b61d]78 before_thread_runs();
79
[f761f1eb]80 /* this is where each thread wakes up after its creation */
[43114c5]81 spinlock_unlock(&THREAD->lock);
[f761f1eb]82 cpu_priority_low();
83
84 f(arg);
85 thread_exit();
86 /* not reached */
87}
88
[70527f1]89
90/** Initialize threads
91 *
92 * Initialize kernel threads support.
93 *
94 */
[f761f1eb]95void thread_init(void)
96{
[43114c5]97 THREAD = NULL;
[f761f1eb]98 nrdy = 0;
99 spinlock_initialize(&threads_lock);
100 list_initialize(&threads_head);
101}
102
[70527f1]103
104/** Make thread ready
105 *
106 * Switch thread t to the ready state.
107 *
108 * @param t Thread to make ready.
109 *
110 */
[f761f1eb]111void thread_ready(thread_t *t)
112{
113 cpu_t *cpu;
114 runq_t *r;
115 pri_t pri;
[4ffa9e0]116 int i, avg, send_ipi = 0;
[f761f1eb]117
118 pri = cpu_priority_high();
119
120 spinlock_lock(&t->lock);
121
122 i = (t->pri < RQ_COUNT -1) ? ++t->pri : t->pri;
123
[8262010]124 cpu = CPU;
[f761f1eb]125 if (t->flags & X_WIRED) {
126 cpu = t->cpu;
127 }
128 spinlock_unlock(&t->lock);
129
[70527f1]130 /*
[f761f1eb]131 * Append t to respective ready queue on respective processor.
132 */
133 r = &cpu->rq[i];
134 spinlock_lock(&r->lock);
135 list_append(&t->rq_link, &r->rq_head);
136 r->n++;
137 spinlock_unlock(&r->lock);
138
[e3f41b6]139 atomic_inc(&nrdy);
140 avg = nrdy / config.cpu_active;
[f761f1eb]141
142 spinlock_lock(&cpu->lock);
[26a8604f]143 if ((++cpu->nrdy) > avg) {
[4ffa9e0]144 /*
145 * If there are idle halted CPU's, this will wake them up.
146 */
[3418c41]147 ipi_broadcast(VECTOR_WAKEUP_IPI);
[4ffa9e0]148 }
[f761f1eb]149 spinlock_unlock(&cpu->lock);
[76cec1e]150
[f761f1eb]151 cpu_priority_restore(pri);
152}
153
[70527f1]154
155/** Create new thread
156 *
157 * Create a new thread.
158 *
159 * @param func Thread's implementing function.
160 * @param arg Thread's implementing function argument.
161 * @param task Task to which the thread belongs.
162 * @param flags Thread flags.
163 *
164 * @return New thread's structure on success, NULL on failure.
165 *
166 */
[f761f1eb]167thread_t *thread_create(void (* func)(void *), void *arg, task_t *task, int flags)
168{
169 thread_t *t;
170 __address frame_ks, frame_us = NULL;
171
172 t = (thread_t *) malloc(sizeof(thread_t));
173 if (t) {
174 pri_t pri;
175
176 spinlock_initialize(&t->lock);
177
178 frame_ks = frame_alloc(FRAME_KA);
179 if (THREAD_USER_STACK & flags) {
[18e0a6c]180 frame_us = frame_alloc(FRAME_KA);
[f761f1eb]181 }
182
183 pri = cpu_priority_high();
184 spinlock_lock(&tidlock);
185 t->tid = ++last_tid;
186 spinlock_unlock(&tidlock);
187 cpu_priority_restore(pri);
188
189 memsetb(frame_ks, THREAD_STACK_SIZE, 0);
190 link_initialize(&t->rq_link);
191 link_initialize(&t->wq_link);
192 link_initialize(&t->th_link);
193 link_initialize(&t->threads_link);
194 t->kstack = (__u8 *) frame_ks;
195 t->ustack = (__u8 *) frame_us;
196
197
198 context_save(&t->saved_context);
[d5d2a3f]199 context_set(&t->saved_context, FADDR(cushion), t->kstack, THREAD_STACK_SIZE);
[bcdd9aa]200
201 the_initialize((the_t *) t->kstack);
[f761f1eb]202
203 pri = cpu_priority_high();
204 t->saved_context.pri = cpu_priority_read();
205 cpu_priority_restore(pri);
206
207 t->thread_code = func;
208 t->thread_arg = arg;
209 t->ticks = -1;
210 t->pri = -1; /* start in rq[0] */
211 t->cpu = NULL;
212 t->flags = 0;
213 t->state = Entering;
214 t->call_me = NULL;
215 t->call_me_with = NULL;
216
217 timeout_initialize(&t->sleep_timeout);
218 t->sleep_queue = NULL;
219 t->timeout_pending = 0;
220
221 t->rwlock_holder_type = RWLOCK_NONE;
222
223 t->task = task;
224
[6a27d63]225 t->fpu_context_exists=0;
226 t->fpu_context_engaged=0;
227
[f761f1eb]228 /*
229 * Register this thread in the system-wide list.
230 */
231 pri = cpu_priority_high();
232 spinlock_lock(&threads_lock);
233 list_append(&t->threads_link, &threads_head);
234 spinlock_unlock(&threads_lock);
235
236 /*
237 * Attach to the containing task.
238 */
239 spinlock_lock(&task->lock);
240 list_append(&t->th_link, &task->th_head);
241 spinlock_unlock(&task->lock);
242
243 cpu_priority_restore(pri);
244 }
245
246 return t;
247}
248
[70527f1]249
250/** Make thread exiting
251 *
252 * End current thread execution and switch it to the exiting
253 * state. All pending timeouts are executed.
254 *
255 */
[f761f1eb]256void thread_exit(void)
257{
258 pri_t pri;
259
260restart:
261 pri = cpu_priority_high();
[43114c5]262 spinlock_lock(&THREAD->lock);
263 if (THREAD->timeout_pending) { /* busy waiting for timeouts in progress */
264 spinlock_unlock(&THREAD->lock);
[f761f1eb]265 cpu_priority_restore(pri);
266 goto restart;
267 }
[43114c5]268 THREAD->state = Exiting;
269 spinlock_unlock(&THREAD->lock);
[f761f1eb]270 scheduler();
271}
272
[70527f1]273
274/** Thread sleep
275 *
276 * Suspend execution of the current thread.
277 *
278 * @param sec Number of seconds to sleep.
279 *
280 */
[f761f1eb]281void thread_sleep(__u32 sec)
282{
[76cec1e]283 thread_usleep(sec*1000000);
[f761f1eb]284}
[70527f1]285
286
287/** Thread usleep
288 *
289 * Suspend execution of the current thread.
290 *
291 * @param usec Number of microseconds to sleep.
292 *
293 */
[f761f1eb]294void thread_usleep(__u32 usec)
295{
296 waitq_t wq;
297
298 waitq_initialize(&wq);
299
300 (void) waitq_sleep_timeout(&wq, usec, SYNCH_NON_BLOCKING);
301}
302
[70527f1]303
304/** Register thread out-of-context invocation
305 *
306 * Register a function and its argument to be executed
307 * on next context switch to the current thread.
308 *
309 * @param call_me Out-of-context function.
310 * @param call_me_with Out-of-context function argument.
311 *
312 */
[f761f1eb]313void thread_register_call_me(void (* call_me)(void *), void *call_me_with)
314{
315 pri_t pri;
316
317 pri = cpu_priority_high();
[43114c5]318 spinlock_lock(&THREAD->lock);
319 THREAD->call_me = call_me;
320 THREAD->call_me_with = call_me_with;
321 spinlock_unlock(&THREAD->lock);
[f761f1eb]322 cpu_priority_restore(pri);
323}
Note: See TracBrowser for help on using the repository browser.