2010-09-22 15:10:42 +02:00
|
|
|
/**
|
|
|
|
* thread functions
|
|
|
|
*
|
2013-06-18 17:21:38 +02:00
|
|
|
* Copyright (C) 2013 Freie Universität Berlin
|
2010-09-22 15:10:42 +02:00
|
|
|
*
|
2013-06-18 17:21:38 +02:00
|
|
|
* This file subject to the terms and conditions of the GNU Lesser General
|
|
|
|
* Public License. See the file LICENSE in the top level directory for more
|
|
|
|
* details.
|
2010-09-22 15:10:42 +02:00
|
|
|
*
|
|
|
|
* @ingroup kernel
|
|
|
|
* @{
|
|
|
|
* @file
|
|
|
|
* @author Kaspar Schleiser <kaspar.schleiser@fu-berlin.de>
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "thread.h"
|
|
|
|
#include "kernel.h"
|
|
|
|
|
2013-07-24 00:36:06 +02:00
|
|
|
#define ENABLE_DEBUG (0)
|
2010-09-22 15:10:42 +02:00
|
|
|
#include "debug.h"
|
2013-07-16 16:36:37 +02:00
|
|
|
#include "kernel_internal.h"
|
2010-09-22 15:10:42 +02:00
|
|
|
#include "bitarithm.h"
|
|
|
|
#include "hwtimer.h"
|
2010-10-28 11:22:57 +02:00
|
|
|
#include "sched.h"
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
inline int thread_getpid()
|
|
|
|
{
|
2010-10-28 11:22:57 +02:00
|
|
|
return active_thread->pid;
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
int thread_getlastpid()
|
|
|
|
{
|
2012-10-18 18:08:40 +02:00
|
|
|
extern int last_pid;
|
|
|
|
return last_pid;
|
|
|
|
}
|
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
unsigned int thread_getstatus(int pid)
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
if (sched_threads[pid] == NULL) {
|
2010-09-22 15:10:42 +02:00
|
|
|
return STATUS_NOT_FOUND;
|
2013-06-20 18:18:29 +02:00
|
|
|
}
|
|
|
|
|
2010-10-28 11:22:57 +02:00
|
|
|
return sched_threads[pid]->status;
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
void thread_sleep()
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
if (inISR()) {
|
2013-06-20 18:18:29 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-22 15:10:42 +02:00
|
|
|
dINT();
|
2013-06-20 18:18:29 +02:00
|
|
|
sched_set_status((tcb_t *)active_thread, STATUS_SLEEPING);
|
2012-11-01 13:18:17 +01:00
|
|
|
eINT();
|
2010-10-28 11:22:57 +02:00
|
|
|
thread_yield();
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
int thread_wakeup(int pid)
|
|
|
|
{
|
2010-11-02 11:40:10 +01:00
|
|
|
DEBUG("thread_wakeup: Trying to wakeup PID %i...\n", pid);
|
2010-09-22 15:10:42 +02:00
|
|
|
int isr = inISR();
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!isr) {
|
2010-11-02 11:40:10 +01:00
|
|
|
DEBUG("thread_wakeup: Not in interrupt.\n");
|
|
|
|
dINT();
|
|
|
|
}
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2010-10-28 11:22:57 +02:00
|
|
|
int result = sched_threads[pid]->status;
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (result == STATUS_SLEEPING) {
|
2010-11-02 11:40:10 +01:00
|
|
|
DEBUG("thread_wakeup: Thread is sleeping.\n");
|
2013-06-20 18:18:29 +02:00
|
|
|
sched_set_status((tcb_t *)sched_threads[pid], STATUS_RUNNING);
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!isr) {
|
2010-09-22 15:10:42 +02:00
|
|
|
eINT();
|
2010-10-28 11:22:57 +02:00
|
|
|
thread_yield();
|
2013-06-20 18:18:29 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-10-28 11:22:57 +02:00
|
|
|
sched_context_switch_request = 1;
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2010-11-04 16:21:39 +01:00
|
|
|
return 1;
|
2013-06-20 18:18:29 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-11-02 11:40:10 +01:00
|
|
|
DEBUG("thread_wakeup: Thread is not sleeping!\n");
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!isr) {
|
2013-06-20 18:18:29 +02:00
|
|
|
eINT();
|
|
|
|
}
|
|
|
|
|
2010-09-22 15:10:42 +02:00
|
|
|
return STATUS_NOT_FOUND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
int thread_measure_stack_usage(char *stack)
|
|
|
|
{
|
|
|
|
unsigned int *stackp = (unsigned int *)stack;
|
|
|
|
|
2010-09-22 15:10:42 +02:00
|
|
|
/* assumption that the comparison fails before or after end of stack */
|
2013-06-24 22:37:35 +02:00
|
|
|
while (*stackp == (unsigned int)stackp) {
|
2010-09-22 15:10:42 +02:00
|
|
|
stackp++;
|
2013-06-20 18:18:29 +02:00
|
|
|
}
|
2010-09-22 15:10:42 +02:00
|
|
|
|
|
|
|
int space = (unsigned int)stackp - (unsigned int)stack;
|
|
|
|
return space;
|
|
|
|
}
|
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
int thread_create(char *stack, int stacksize, char priority, int flags, void (*function)(void), const char *name)
|
2010-09-22 15:10:42 +02:00
|
|
|
{
|
2010-11-04 16:47:24 +01:00
|
|
|
/* allocate our thread control block at the top of our stackspace */
|
|
|
|
int total_stacksize = stacksize;
|
2011-03-08 11:43:21 +01:00
|
|
|
stacksize -= sizeof(tcb_t);
|
2010-11-09 17:01:52 +01:00
|
|
|
|
|
|
|
/* align tcb address on 32bit boundary */
|
|
|
|
unsigned int tcb_address = (unsigned int) stack + stacksize;
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (tcb_address & 1) {
|
2010-11-09 17:01:52 +01:00
|
|
|
tcb_address--;
|
|
|
|
stacksize--;
|
|
|
|
}
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (tcb_address & 2) {
|
2013-06-20 18:18:29 +02:00
|
|
|
tcb_address -= 2;
|
|
|
|
stacksize -= 2;
|
2010-11-09 17:01:52 +01:00
|
|
|
}
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
tcb_t *cb = (tcb_t *) tcb_address;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (priority >= SCHED_PRIO_LEVELS) {
|
2010-09-22 15:10:42 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (flags & CREATE_STACKTEST) {
|
2010-09-22 15:10:42 +02:00
|
|
|
/* assign each int of the stack the value of it's address */
|
2013-06-20 18:18:29 +02:00
|
|
|
unsigned int *stackmax = (unsigned int *)((char *)stack + stacksize);
|
|
|
|
unsigned int *stackp = (unsigned int *)stack;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
while (stackp < stackmax) {
|
2010-09-22 15:10:42 +02:00
|
|
|
*stackp = (unsigned int)stackp;
|
|
|
|
stackp++;
|
|
|
|
}
|
2013-06-20 18:18:29 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-09-22 15:10:42 +02:00
|
|
|
/* create stack guard */
|
|
|
|
*stack = (unsigned int)stack;
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!inISR()) {
|
2010-09-22 15:10:42 +02:00
|
|
|
dINT();
|
|
|
|
}
|
|
|
|
|
|
|
|
int pid = 0;
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
while (pid < MAXTHREADS) {
|
|
|
|
if (sched_threads[pid] == NULL) {
|
2010-10-28 11:22:57 +02:00
|
|
|
sched_threads[pid] = cb;
|
2010-10-28 11:31:19 +02:00
|
|
|
cb->pid = pid;
|
2010-09-22 15:10:42 +02:00
|
|
|
break;
|
|
|
|
}
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2010-09-22 15:10:42 +02:00
|
|
|
pid++;
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (pid == MAXTHREADS) {
|
2010-09-22 15:10:42 +02:00
|
|
|
DEBUG("thread_create(): too many threads!\n");
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!inISR()) {
|
2010-09-22 15:10:42 +02:00
|
|
|
eINT();
|
|
|
|
}
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2010-09-22 15:10:42 +02:00
|
|
|
return -EOVERFLOW;
|
|
|
|
}
|
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
cb->sp = thread_stack_init(function, stack, stacksize);
|
2010-10-25 15:40:01 +02:00
|
|
|
cb->stack_start = stack;
|
2010-11-04 16:47:24 +01:00
|
|
|
cb->stack_size = total_stacksize;
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2010-10-25 15:40:01 +02:00
|
|
|
cb->priority = priority;
|
|
|
|
cb->status = 0;
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2010-11-26 14:21:48 +01:00
|
|
|
cb->rq_entry.data = (unsigned int) cb;
|
|
|
|
cb->rq_entry.next = NULL;
|
|
|
|
cb->rq_entry.prev = NULL;
|
|
|
|
|
2010-10-25 15:40:01 +02:00
|
|
|
cb->name = name;
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2010-10-25 15:40:01 +02:00
|
|
|
cb->wait_data = NULL;
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2010-11-26 14:21:48 +01:00
|
|
|
cb->msg_waiters.data = 0;
|
|
|
|
cb->msg_waiters.priority = 0;
|
|
|
|
cb->msg_waiters.next = NULL;
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-06-20 18:18:29 +02:00
|
|
|
cib_init(&(cb->msg_queue), 0);
|
2010-11-26 15:02:15 +01:00
|
|
|
cb->msg_array = NULL;
|
2010-09-22 15:10:42 +02:00
|
|
|
|
|
|
|
num_tasks++;
|
|
|
|
|
2010-10-25 15:40:01 +02:00
|
|
|
DEBUG("Created thread %s. PID: %u. Priority: %u.\n", name, cb->pid, priority);
|
2010-09-22 15:10:42 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (flags & CREATE_SLEEPING) {
|
2010-10-25 15:40:01 +02:00
|
|
|
sched_set_status(cb, STATUS_SLEEPING);
|
2013-06-20 18:18:29 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-10-25 15:40:01 +02:00
|
|
|
sched_set_status(cb, STATUS_PENDING);
|
2013-06-20 18:18:29 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!(flags & CREATE_WOUT_YIELD)) {
|
|
|
|
if (!inISR()) {
|
2010-09-22 15:10:42 +02:00
|
|
|
eINT();
|
2010-10-28 11:22:57 +02:00
|
|
|
thread_yield();
|
2013-06-20 18:18:29 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-10-28 11:22:57 +02:00
|
|
|
sched_context_switch_request = 1;
|
2010-09-22 15:10:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!inISR() && active_thread != NULL) {
|
2010-09-22 15:10:42 +02:00
|
|
|
eINT();
|
|
|
|
}
|
|
|
|
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|