source: mainline/kernel/generic/src/proc/thread.c@ 314f4b59

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 314f4b59 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 25.3 KB
Line 
1/*
2 * Copyright (c) 2010 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/** @addtogroup genericproc
30 * @{
31 */
32
33/**
34 * @file
35 * @brief Thread management functions.
36 */
37
38#include <assert.h>
39#include <proc/scheduler.h>
40#include <proc/thread.h>
41#include <proc/task.h>
42#include <mm/frame.h>
43#include <mm/page.h>
44#include <arch/asm.h>
45#include <arch/cycle.h>
46#include <arch.h>
47#include <synch/spinlock.h>
48#include <synch/waitq.h>
49#include <synch/workqueue.h>
50#include <synch/rcu.h>
51#include <cpu.h>
52#include <str.h>
53#include <context.h>
54#include <adt/avl.h>
55#include <adt/list.h>
56#include <time/clock.h>
57#include <time/timeout.h>
58#include <time/delay.h>
59#include <config.h>
60#include <arch/interrupt.h>
61#include <smp/ipi.h>
62#include <arch/faddr.h>
63#include <atomic.h>
64#include <mem.h>
65#include <print.h>
66#include <mm/slab.h>
67#include <main/uinit.h>
68#include <syscall/copy.h>
69#include <errno.h>
70
71/** Thread states */
72const char *thread_states[] = {
73 "Invalid",
74 "Running",
75 "Sleeping",
76 "Ready",
77 "Entering",
78 "Exiting",
79 "Lingering"
80};
81
82typedef struct {
83 thread_id_t thread_id;
84 thread_t *thread;
85} thread_iterator_t;
86
87/** Lock protecting the threads_tree AVL tree.
88 *
89 * For locking rules, see declaration thereof.
90 *
91 */
92IRQ_SPINLOCK_INITIALIZE(threads_lock);
93
94/** AVL tree of all threads.
95 *
96 * When a thread is found in the threads_tree AVL tree, it is guaranteed to
97 * exist as long as the threads_lock is held.
98 *
99 */
100avltree_t threads_tree;
101
102IRQ_SPINLOCK_STATIC_INITIALIZE(tidlock);
103static thread_id_t last_tid = 0;
104
105static slab_cache_t *thread_cache;
106
107#ifdef CONFIG_FPU
108slab_cache_t *fpu_context_cache;
109#endif
110
111/** Thread wrapper.
112 *
113 * This wrapper is provided to ensure that every thread makes a call to
114 * thread_exit() when its implementing function returns.
115 *
116 * interrupts_disable() is assumed.
117 *
118 */
119static void cushion(void)
120{
121 void (*f)(void *) = THREAD->thread_code;
122 void *arg = THREAD->thread_arg;
123 THREAD->last_cycle = get_cycle();
124
125 /* This is where each thread wakes up after its creation */
126 irq_spinlock_unlock(&THREAD->lock, false);
127 interrupts_enable();
128
129 f(arg);
130
131 /* Accumulate accounting to the task */
132 irq_spinlock_lock(&THREAD->lock, true);
133 if (!THREAD->uncounted) {
134 thread_update_accounting(true);
135 uint64_t ucycles = THREAD->ucycles;
136 THREAD->ucycles = 0;
137 uint64_t kcycles = THREAD->kcycles;
138 THREAD->kcycles = 0;
139
140 irq_spinlock_pass(&THREAD->lock, &TASK->lock);
141 TASK->ucycles += ucycles;
142 TASK->kcycles += kcycles;
143 irq_spinlock_unlock(&TASK->lock, true);
144 } else
145 irq_spinlock_unlock(&THREAD->lock, true);
146
147 thread_exit();
148
149 /* Not reached */
150}
151
152/** Initialization and allocation for thread_t structure
153 *
154 */
155static errno_t thr_constructor(void *obj, unsigned int kmflags)
156{
157 thread_t *thread = (thread_t *) obj;
158
159 irq_spinlock_initialize(&thread->lock, "thread_t_lock");
160 link_initialize(&thread->rq_link);
161 link_initialize(&thread->wq_link);
162 link_initialize(&thread->th_link);
163
164 /* call the architecture-specific part of the constructor */
165 thr_constructor_arch(thread);
166
167#ifdef CONFIG_FPU
168#ifdef CONFIG_FPU_LAZY
169 thread->saved_fpu_context = NULL;
170#else /* CONFIG_FPU_LAZY */
171 thread->saved_fpu_context = slab_alloc(fpu_context_cache, kmflags);
172 if (!thread->saved_fpu_context)
173 return ENOMEM;
174#endif /* CONFIG_FPU_LAZY */
175#endif /* CONFIG_FPU */
176
177 /*
178 * Allocate the kernel stack from the low-memory to prevent an infinite
179 * nesting of TLB-misses when accessing the stack from the part of the
180 * TLB-miss handler written in C.
181 *
182 * Note that low-memory is safe to be used for the stack as it will be
183 * covered by the kernel identity mapping, which guarantees not to
184 * nest TLB-misses infinitely (either via some hardware mechanism or
185 * by the construciton of the assembly-language part of the TLB-miss
186 * handler).
187 *
188 * This restriction can be lifted once each architecture provides
189 * a similar guarantee, for example by locking the kernel stack
190 * in the TLB whenever it is allocated from the high-memory and the
191 * thread is being scheduled to run.
192 */
193 kmflags |= FRAME_LOWMEM;
194 kmflags &= ~FRAME_HIGHMEM;
195
196 uintptr_t stack_phys =
197 frame_alloc(STACK_FRAMES, kmflags, STACK_SIZE - 1);
198 if (!stack_phys) {
199#ifdef CONFIG_FPU
200 if (thread->saved_fpu_context)
201 slab_free(fpu_context_cache, thread->saved_fpu_context);
202#endif
203 return ENOMEM;
204 }
205
206 thread->kstack = (uint8_t *) PA2KA(stack_phys);
207
208#ifdef CONFIG_UDEBUG
209 mutex_initialize(&thread->udebug.lock, MUTEX_PASSIVE);
210#endif
211
212 return EOK;
213}
214
215/** Destruction of thread_t object */
216static size_t thr_destructor(void *obj)
217{
218 thread_t *thread = (thread_t *) obj;
219
220 /* call the architecture-specific part of the destructor */
221 thr_destructor_arch(thread);
222
223 frame_free(KA2PA(thread->kstack), STACK_FRAMES);
224
225#ifdef CONFIG_FPU
226 if (thread->saved_fpu_context)
227 slab_free(fpu_context_cache, thread->saved_fpu_context);
228#endif
229
230 return STACK_FRAMES; /* number of frames freed */
231}
232
233/** Initialize threads
234 *
235 * Initialize kernel threads support.
236 *
237 */
238void thread_init(void)
239{
240 THREAD = NULL;
241
242 atomic_set(&nrdy, 0);
243 thread_cache = slab_cache_create("thread_t", sizeof(thread_t), 0,
244 thr_constructor, thr_destructor, 0);
245
246#ifdef CONFIG_FPU
247 fpu_context_cache = slab_cache_create("fpu_context_t",
248 sizeof(fpu_context_t), FPU_CONTEXT_ALIGN, NULL, NULL, 0);
249#endif
250
251 avltree_create(&threads_tree);
252}
253
254/** Wire thread to the given CPU
255 *
256 * @param cpu CPU to wire the thread to.
257 *
258 */
259void thread_wire(thread_t *thread, cpu_t *cpu)
260{
261 irq_spinlock_lock(&thread->lock, true);
262 thread->cpu = cpu;
263 thread->wired = true;
264 irq_spinlock_unlock(&thread->lock, true);
265}
266
267/** Invoked right before thread_ready() readies the thread. thread is locked. */
268static void before_thread_is_ready(thread_t *thread)
269{
270 assert(irq_spinlock_locked(&thread->lock));
271 workq_before_thread_is_ready(thread);
272}
273
274/** Make thread ready
275 *
276 * Switch thread to the ready state.
277 *
278 * @param thread Thread to make ready.
279 *
280 */
281void thread_ready(thread_t *thread)
282{
283 irq_spinlock_lock(&thread->lock, true);
284
285 assert(thread->state != Ready);
286
287 before_thread_is_ready(thread);
288
289 int i = (thread->priority < RQ_COUNT - 1) ?
290 ++thread->priority : thread->priority;
291
292 cpu_t *cpu;
293 if (thread->wired || thread->nomigrate || thread->fpu_context_engaged) {
294 /* Cannot ready to another CPU */
295 assert(thread->cpu != NULL);
296 cpu = thread->cpu;
297 } else if (thread->stolen) {
298 /* Ready to the stealing CPU */
299 cpu = CPU;
300 } else if (thread->cpu) {
301 /* Prefer the CPU on which the thread ran last */
302 assert(thread->cpu != NULL);
303 cpu = thread->cpu;
304 } else {
305 cpu = CPU;
306 }
307
308 thread->state = Ready;
309
310 irq_spinlock_pass(&thread->lock, &(cpu->rq[i].lock));
311
312 /*
313 * Append thread to respective ready queue
314 * on respective processor.
315 */
316
317 list_append(&thread->rq_link, &cpu->rq[i].rq);
318 cpu->rq[i].n++;
319 irq_spinlock_unlock(&(cpu->rq[i].lock), true);
320
321 atomic_inc(&nrdy);
322 atomic_inc(&cpu->nrdy);
323}
324
325/** Create new thread
326 *
327 * Create a new thread.
328 *
329 * @param func Thread's implementing function.
330 * @param arg Thread's implementing function argument.
331 * @param task Task to which the thread belongs. The caller must
332 * guarantee that the task won't cease to exist during the
333 * call. The task's lock may not be held.
334 * @param flags Thread flags.
335 * @param name Symbolic name (a copy is made).
336 *
337 * @return New thread's structure on success, NULL on failure.
338 *
339 */
340thread_t *thread_create(void (* func)(void *), void *arg, task_t *task,
341 thread_flags_t flags, const char *name)
342{
343 thread_t *thread = (thread_t *) slab_alloc(thread_cache, 0);
344 if (!thread)
345 return NULL;
346
347 /* Not needed, but good for debugging */
348 memsetb(thread->kstack, STACK_SIZE, 0);
349
350 irq_spinlock_lock(&tidlock, true);
351 thread->tid = ++last_tid;
352 irq_spinlock_unlock(&tidlock, true);
353
354 context_save(&thread->saved_context);
355 context_set(&thread->saved_context, FADDR(cushion),
356 (uintptr_t) thread->kstack, STACK_SIZE);
357
358 the_initialize((the_t *) thread->kstack);
359
360 ipl_t ipl = interrupts_disable();
361 thread->saved_context.ipl = interrupts_read();
362 interrupts_restore(ipl);
363
364 str_cpy(thread->name, THREAD_NAME_BUFLEN, name);
365
366 thread->thread_code = func;
367 thread->thread_arg = arg;
368 thread->ticks = -1;
369 thread->ucycles = 0;
370 thread->kcycles = 0;
371 thread->uncounted =
372 ((flags & THREAD_FLAG_UNCOUNTED) == THREAD_FLAG_UNCOUNTED);
373 thread->priority = -1; /* Start in rq[0] */
374 thread->cpu = NULL;
375 thread->wired = false;
376 thread->stolen = false;
377 thread->uspace =
378 ((flags & THREAD_FLAG_USPACE) == THREAD_FLAG_USPACE);
379
380 thread->nomigrate = 0;
381 thread->state = Entering;
382
383 timeout_initialize(&thread->sleep_timeout);
384 thread->sleep_interruptible = false;
385 thread->sleep_queue = NULL;
386 thread->timeout_pending = false;
387
388 thread->in_copy_from_uspace = false;
389 thread->in_copy_to_uspace = false;
390
391 thread->interrupted = false;
392 thread->detached = false;
393 waitq_initialize(&thread->join_wq);
394
395 thread->task = task;
396
397 thread->workq = NULL;
398
399 thread->fpu_context_exists = false;
400 thread->fpu_context_engaged = false;
401
402 avltree_node_initialize(&thread->threads_tree_node);
403 thread->threads_tree_node.key = (uintptr_t) thread;
404
405#ifdef CONFIG_UDEBUG
406 /* Initialize debugging stuff */
407 thread->btrace = false;
408 udebug_thread_initialize(&thread->udebug);
409#endif
410
411 /* Might depend on previous initialization */
412 thread_create_arch(thread);
413
414 rcu_thread_init(thread);
415
416 if ((flags & THREAD_FLAG_NOATTACH) != THREAD_FLAG_NOATTACH)
417 thread_attach(thread, task);
418
419 return thread;
420}
421
422/** Destroy thread memory structure
423 *
424 * Detach thread from all queues, cpus etc. and destroy it.
425 *
426 * @param thread Thread to be destroyed.
427 * @param irq_res Indicate whether it should unlock thread->lock
428 * in interrupts-restore mode.
429 *
430 */
431void thread_destroy(thread_t *thread, bool irq_res)
432{
433 assert(irq_spinlock_locked(&thread->lock));
434 assert((thread->state == Exiting) || (thread->state == Lingering));
435 assert(thread->task);
436 assert(thread->cpu);
437
438 irq_spinlock_lock(&thread->cpu->lock, false);
439 if (thread->cpu->fpu_owner == thread)
440 thread->cpu->fpu_owner = NULL;
441 irq_spinlock_unlock(&thread->cpu->lock, false);
442
443 irq_spinlock_pass(&thread->lock, &threads_lock);
444
445 avltree_delete(&threads_tree, &thread->threads_tree_node);
446
447 irq_spinlock_pass(&threads_lock, &thread->task->lock);
448
449 /*
450 * Detach from the containing task.
451 */
452 list_remove(&thread->th_link);
453 irq_spinlock_unlock(&thread->task->lock, irq_res);
454
455 /*
456 * Drop the reference to the containing task.
457 */
458 task_release(thread->task);
459 slab_free(thread_cache, thread);
460}
461
462/** Make the thread visible to the system.
463 *
464 * Attach the thread structure to the current task and make it visible in the
465 * threads_tree.
466 *
467 * @param t Thread to be attached to the task.
468 * @param task Task to which the thread is to be attached.
469 *
470 */
471void thread_attach(thread_t *thread, task_t *task)
472{
473 /*
474 * Attach to the specified task.
475 */
476 irq_spinlock_lock(&task->lock, true);
477
478 /* Hold a reference to the task. */
479 task_hold(task);
480
481 /* Must not count kbox thread into lifecount */
482 if (thread->uspace)
483 atomic_inc(&task->lifecount);
484
485 list_append(&thread->th_link, &task->threads);
486
487 irq_spinlock_pass(&task->lock, &threads_lock);
488
489 /*
490 * Register this thread in the system-wide list.
491 */
492 avltree_insert(&threads_tree, &thread->threads_tree_node);
493 irq_spinlock_unlock(&threads_lock, true);
494}
495
496/** Terminate thread.
497 *
498 * End current thread execution and switch it to the exiting state.
499 * All pending timeouts are executed.
500 *
501 */
502void thread_exit(void)
503{
504 if (THREAD->uspace) {
505#ifdef CONFIG_UDEBUG
506 /* Generate udebug THREAD_E event */
507 udebug_thread_e_event();
508
509 /*
510 * This thread will not execute any code or system calls from
511 * now on.
512 */
513 udebug_stoppable_begin();
514#endif
515 if (atomic_predec(&TASK->lifecount) == 0) {
516 /*
517 * We are the last userspace thread in the task that
518 * still has not exited. With the exception of the
519 * moment the task was created, new userspace threads
520 * can only be created by threads of the same task.
521 * We are safe to perform cleanup.
522 *
523 */
524 ipc_cleanup();
525 futex_task_cleanup();
526 LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid);
527 }
528 }
529
530restart:
531 irq_spinlock_lock(&THREAD->lock, true);
532 if (THREAD->timeout_pending) {
533 /* Busy waiting for timeouts in progress */
534 irq_spinlock_unlock(&THREAD->lock, true);
535 goto restart;
536 }
537
538 THREAD->state = Exiting;
539 irq_spinlock_unlock(&THREAD->lock, true);
540
541 scheduler();
542
543 /* Not reached */
544 while (true);
545}
546
547/** Interrupts an existing thread so that it may exit as soon as possible.
548 *
549 * Threads that are blocked waiting for a synchronization primitive
550 * are woken up with a return code of EINTR if the
551 * blocking call was interruptable. See waitq_sleep_timeout().
552 *
553 * The caller must guarantee the thread object is valid during the entire
554 * function, eg by holding the threads_lock lock.
555 *
556 * Interrupted threads automatically exit when returning back to user space.
557 *
558 * @param thread A valid thread object. The caller must guarantee it
559 * will remain valid until thread_interrupt() exits.
560 */
561void thread_interrupt(thread_t *thread)
562{
563 assert(thread != NULL);
564
565 irq_spinlock_lock(&thread->lock, true);
566
567 thread->interrupted = true;
568 bool sleeping = (thread->state == Sleeping);
569
570 irq_spinlock_unlock(&thread->lock, true);
571
572 if (sleeping)
573 waitq_interrupt_sleep(thread);
574}
575
576/** Returns true if the thread was interrupted.
577 *
578 * @param thread A valid thread object. User must guarantee it will
579 * be alive during the entire call.
580 * @return true if the thread was already interrupted via thread_interrupt().
581 */
582bool thread_interrupted(thread_t *thread)
583{
584 assert(thread != NULL);
585
586 bool interrupted;
587
588 irq_spinlock_lock(&thread->lock, true);
589 interrupted = thread->interrupted;
590 irq_spinlock_unlock(&thread->lock, true);
591
592 return interrupted;
593}
594
595/** Prevent the current thread from being migrated to another processor. */
596void thread_migration_disable(void)
597{
598 assert(THREAD);
599
600 THREAD->nomigrate++;
601}
602
603/** Allow the current thread to be migrated to another processor. */
604void thread_migration_enable(void)
605{
606 assert(THREAD);
607 assert(THREAD->nomigrate > 0);
608
609 if (THREAD->nomigrate > 0)
610 THREAD->nomigrate--;
611}
612
613/** Thread sleep
614 *
615 * Suspend execution of the current thread.
616 *
617 * @param sec Number of seconds to sleep.
618 *
619 */
620void thread_sleep(uint32_t sec)
621{
622 /* Sleep in 1000 second steps to support
623 full argument range */
624 while (sec > 0) {
625 uint32_t period = (sec > 1000) ? 1000 : sec;
626
627 thread_usleep(period * 1000000);
628 sec -= period;
629 }
630}
631
632/** Wait for another thread to exit.
633 *
634 * @param thread Thread to join on exit.
635 * @param usec Timeout in microseconds.
636 * @param flags Mode of operation.
637 *
638 * @return An error code from errno.h or an error code from synch.h.
639 *
640 */
641errno_t thread_join_timeout(thread_t *thread, uint32_t usec, unsigned int flags)
642{
643 if (thread == THREAD)
644 return EINVAL;
645
646 /*
647 * Since thread join can only be called once on an undetached thread,
648 * the thread pointer is guaranteed to be still valid.
649 */
650
651 irq_spinlock_lock(&thread->lock, true);
652 assert(!thread->detached);
653 irq_spinlock_unlock(&thread->lock, true);
654
655 return waitq_sleep_timeout(&thread->join_wq, usec, flags, NULL);
656}
657
658/** Detach thread.
659 *
660 * Mark the thread as detached. If the thread is already
661 * in the Lingering state, deallocate its resources.
662 *
663 * @param thread Thread to be detached.
664 *
665 */
666void thread_detach(thread_t *thread)
667{
668 /*
669 * Since the thread is expected not to be already detached,
670 * pointer to it must be still valid.
671 */
672 irq_spinlock_lock(&thread->lock, true);
673 assert(!thread->detached);
674
675 if (thread->state == Lingering) {
676 /*
677 * Unlock &thread->lock and restore
678 * interrupts in thread_destroy().
679 */
680 thread_destroy(thread, true);
681 return;
682 } else {
683 thread->detached = true;
684 }
685
686 irq_spinlock_unlock(&thread->lock, true);
687}
688
689/** Thread usleep
690 *
691 * Suspend execution of the current thread.
692 *
693 * @param usec Number of microseconds to sleep.
694 *
695 */
696void thread_usleep(uint32_t usec)
697{
698 waitq_t wq;
699
700 waitq_initialize(&wq);
701
702 (void) waitq_sleep_timeout(&wq, usec, SYNCH_FLAGS_NON_BLOCKING, NULL);
703}
704
705static bool thread_walker(avltree_node_t *node, void *arg)
706{
707 bool *additional = (bool *) arg;
708 thread_t *thread = avltree_get_instance(node, thread_t, threads_tree_node);
709
710 uint64_t ucycles, kcycles;
711 char usuffix, ksuffix;
712 order_suffix(thread->ucycles, &ucycles, &usuffix);
713 order_suffix(thread->kcycles, &kcycles, &ksuffix);
714
715 char *name;
716 if (str_cmp(thread->name, "uinit") == 0)
717 name = thread->task->name;
718 else
719 name = thread->name;
720
721#ifdef __32_BITS__
722 if (*additional)
723 printf("%-8" PRIu64 " %10p %10p %9" PRIu64 "%c %9" PRIu64 "%c ",
724 thread->tid, thread->thread_code, thread->kstack,
725 ucycles, usuffix, kcycles, ksuffix);
726 else
727 printf("%-8" PRIu64 " %-14s %10p %-8s %10p %-5" PRIu32 "\n",
728 thread->tid, name, thread, thread_states[thread->state],
729 thread->task, thread->task->container);
730#endif
731
732#ifdef __64_BITS__
733 if (*additional)
734 printf("%-8" PRIu64 " %18p %18p\n"
735 " %9" PRIu64 "%c %9" PRIu64 "%c ",
736 thread->tid, thread->thread_code, thread->kstack,
737 ucycles, usuffix, kcycles, ksuffix);
738 else
739 printf("%-8" PRIu64 " %-14s %18p %-8s %18p %-5" PRIu32 "\n",
740 thread->tid, name, thread, thread_states[thread->state],
741 thread->task, thread->task->container);
742#endif
743
744 if (*additional) {
745 if (thread->cpu)
746 printf("%-5u", thread->cpu->id);
747 else
748 printf("none ");
749
750 if (thread->state == Sleeping) {
751#ifdef __32_BITS__
752 printf(" %10p", thread->sleep_queue);
753#endif
754
755#ifdef __64_BITS__
756 printf(" %18p", thread->sleep_queue);
757#endif
758 }
759
760 printf("\n");
761 }
762
763 return true;
764}
765
766/** Print list of threads debug info
767 *
768 * @param additional Print additional information.
769 *
770 */
771void thread_print_list(bool additional)
772{
773 /* Messing with thread structures, avoid deadlock */
774 irq_spinlock_lock(&threads_lock, true);
775
776#ifdef __32_BITS__
777 if (additional)
778 printf("[id ] [code ] [stack ] [ucycles ] [kcycles ]"
779 " [cpu] [waitqueue]\n");
780 else
781 printf("[id ] [name ] [address ] [state ] [task ]"
782 " [ctn]\n");
783#endif
784
785#ifdef __64_BITS__
786 if (additional) {
787 printf("[id ] [code ] [stack ]\n"
788 " [ucycles ] [kcycles ] [cpu] [waitqueue ]\n");
789 } else
790 printf("[id ] [name ] [address ] [state ]"
791 " [task ] [ctn]\n");
792#endif
793
794 avltree_walk(&threads_tree, thread_walker, &additional);
795
796 irq_spinlock_unlock(&threads_lock, true);
797}
798
799/** Check whether thread exists.
800 *
801 * Note that threads_lock must be already held and
802 * interrupts must be already disabled.
803 *
804 * @param thread Pointer to thread.
805 *
806 * @return True if thread t is known to the system, false otherwise.
807 *
808 */
809bool thread_exists(thread_t *thread)
810{
811 assert(interrupts_disabled());
812 assert(irq_spinlock_locked(&threads_lock));
813
814 avltree_node_t *node =
815 avltree_search(&threads_tree, (avltree_key_t) ((uintptr_t) thread));
816
817 return node != NULL;
818}
819
820/** Update accounting of current thread.
821 *
822 * Note that thread_lock on THREAD must be already held and
823 * interrupts must be already disabled.
824 *
825 * @param user True to update user accounting, false for kernel.
826 *
827 */
828void thread_update_accounting(bool user)
829{
830 uint64_t time = get_cycle();
831
832 assert(interrupts_disabled());
833 assert(irq_spinlock_locked(&THREAD->lock));
834
835 if (user)
836 THREAD->ucycles += time - THREAD->last_cycle;
837 else
838 THREAD->kcycles += time - THREAD->last_cycle;
839
840 THREAD->last_cycle = time;
841}
842
843static bool thread_search_walker(avltree_node_t *node, void *arg)
844{
845 thread_t *thread =
846 (thread_t *) avltree_get_instance(node, thread_t, threads_tree_node);
847 thread_iterator_t *iterator = (thread_iterator_t *) arg;
848
849 if (thread->tid == iterator->thread_id) {
850 iterator->thread = thread;
851 return false;
852 }
853
854 return true;
855}
856
857/** Find thread structure corresponding to thread ID.
858 *
859 * The threads_lock must be already held by the caller of this function and
860 * interrupts must be disabled.
861 *
862 * @param id Thread ID.
863 *
864 * @return Thread structure address or NULL if there is no such thread ID.
865 *
866 */
867thread_t *thread_find_by_id(thread_id_t thread_id)
868{
869 assert(interrupts_disabled());
870 assert(irq_spinlock_locked(&threads_lock));
871
872 thread_iterator_t iterator;
873
874 iterator.thread_id = thread_id;
875 iterator.thread = NULL;
876
877 avltree_walk(&threads_tree, thread_search_walker, (void *) &iterator);
878
879 return iterator.thread;
880}
881
882#ifdef CONFIG_UDEBUG
883
884void thread_stack_trace(thread_id_t thread_id)
885{
886 irq_spinlock_lock(&threads_lock, true);
887
888 thread_t *thread = thread_find_by_id(thread_id);
889 if (thread == NULL) {
890 printf("No such thread.\n");
891 irq_spinlock_unlock(&threads_lock, true);
892 return;
893 }
894
895 irq_spinlock_lock(&thread->lock, false);
896
897 /*
898 * Schedule a stack trace to be printed
899 * just before the thread is scheduled next.
900 *
901 * If the thread is sleeping then try to interrupt
902 * the sleep. Any request for printing an uspace stack
903 * trace from within the kernel should be always
904 * considered a last resort debugging means, therefore
905 * forcing the thread's sleep to be interrupted
906 * is probably justifiable.
907 */
908
909 bool sleeping = false;
910 istate_t *istate = thread->udebug.uspace_state;
911 if (istate != NULL) {
912 printf("Scheduling thread stack trace.\n");
913 thread->btrace = true;
914 if (thread->state == Sleeping)
915 sleeping = true;
916 } else
917 printf("Thread interrupt state not available.\n");
918
919 irq_spinlock_unlock(&thread->lock, false);
920
921 if (sleeping)
922 waitq_interrupt_sleep(thread);
923
924 irq_spinlock_unlock(&threads_lock, true);
925}
926
927#endif /* CONFIG_UDEBUG */
928
929/** Process syscall to create new thread.
930 *
931 */
932sys_errno_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name,
933 size_t name_len, thread_id_t *uspace_thread_id)
934{
935 if (name_len > THREAD_NAME_BUFLEN - 1)
936 name_len = THREAD_NAME_BUFLEN - 1;
937
938 char namebuf[THREAD_NAME_BUFLEN];
939 errno_t rc = copy_from_uspace(namebuf, uspace_name, name_len);
940 if (rc != EOK)
941 return (sys_errno_t) rc;
942
943 namebuf[name_len] = 0;
944
945 /*
946 * In case of failure, kernel_uarg will be deallocated in this function.
947 * In case of success, kernel_uarg will be freed in uinit().
948 */
949 uspace_arg_t *kernel_uarg =
950 (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
951
952 rc = copy_from_uspace(kernel_uarg, uspace_uarg, sizeof(uspace_arg_t));
953 if (rc != EOK) {
954 free(kernel_uarg);
955 return (sys_errno_t) rc;
956 }
957
958 thread_t *thread = thread_create(uinit, kernel_uarg, TASK,
959 THREAD_FLAG_USPACE | THREAD_FLAG_NOATTACH, namebuf);
960 if (thread) {
961 if (uspace_thread_id != NULL) {
962 rc = copy_to_uspace(uspace_thread_id, &thread->tid,
963 sizeof(thread->tid));
964 if (rc != EOK) {
965 /*
966 * We have encountered a failure, but the thread
967 * has already been created. We need to undo its
968 * creation now.
969 */
970
971 /*
972 * The new thread structure is initialized, but
973 * is still not visible to the system.
974 * We can safely deallocate it.
975 */
976 slab_free(thread_cache, thread);
977 free(kernel_uarg);
978
979 return (sys_errno_t) rc;
980 }
981 }
982
983#ifdef CONFIG_UDEBUG
984 /*
985 * Generate udebug THREAD_B event and attach the thread.
986 * This must be done atomically (with the debug locks held),
987 * otherwise we would either miss some thread or receive
988 * THREAD_B events for threads that already existed
989 * and could be detected with THREAD_READ before.
990 */
991 udebug_thread_b_event_attach(thread, TASK);
992#else
993 thread_attach(thread, TASK);
994#endif
995 thread_ready(thread);
996
997 return 0;
998 } else
999 free(kernel_uarg);
1000
1001 return (sys_errno_t) ENOMEM;
1002}
1003
1004/** Process syscall to terminate thread.
1005 *
1006 */
1007sys_errno_t sys_thread_exit(int uspace_status)
1008{
1009 thread_exit();
1010}
1011
1012/** Syscall for getting TID.
1013 *
1014 * @param uspace_thread_id Userspace address of 8-byte buffer where to store
1015 * current thread ID.
1016 *
1017 * @return 0 on success or an error code from @ref errno.h.
1018 *
1019 */
1020sys_errno_t sys_thread_get_id(thread_id_t *uspace_thread_id)
1021{
1022 /*
1023 * No need to acquire lock on THREAD because tid
1024 * remains constant for the lifespan of the thread.
1025 *
1026 */
1027 return (sys_errno_t) copy_to_uspace(uspace_thread_id, &THREAD->tid,
1028 sizeof(THREAD->tid));
1029}
1030
1031/** Syscall wrapper for sleeping. */
1032sys_errno_t sys_thread_usleep(uint32_t usec)
1033{
1034 thread_usleep(usec);
1035 return 0;
1036}
1037
1038sys_errno_t sys_thread_udelay(uint32_t usec)
1039{
1040 delay(usec);
1041 return 0;
1042}
1043
1044/** @}
1045 */
Note: See TracBrowser for help on using the repository browser.