2006-02-03 15:19:58 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 Dan Everton
|
|
|
|
*
|
2008-06-28 18:10:04 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2006-02-03 15:19:58 +00:00
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2007-09-10 03:49:12 +00:00
|
|
|
#include <stdbool.h>
|
2006-02-03 15:19:58 +00:00
|
|
|
#include <time.h>
|
|
|
|
#include <SDL.h>
|
|
|
|
#include <SDL_thread.h>
|
|
|
|
#include <stdlib.h>
|
2010-05-16 12:43:09 +00:00
|
|
|
#include <string.h> /* memset() */
|
2007-09-10 03:49:12 +00:00
|
|
|
#include <setjmp.h>
|
2007-10-26 23:11:18 +00:00
|
|
|
#include "system-sdl.h"
|
2006-02-03 15:19:58 +00:00
|
|
|
#include "thread-sdl.h"
|
2014-08-08 05:39:29 +00:00
|
|
|
#include "../kernel-internal.h"
|
2014-01-09 20:37:07 +00:00
|
|
|
#include "core_alloc.h"
|
2006-02-03 15:19:58 +00:00
|
|
|
|
2007-09-08 12:20:53 +00:00
|
|
|
/* Define this as 1 to show informational messages that are not errors. */
|
2014-08-08 10:33:51 +00:00
|
|
|
#define THREAD_SDL_DEBUGF_ENABLED 1
|
2006-02-03 15:19:58 +00:00
|
|
|
|
2007-09-08 12:20:53 +00:00
|
|
|
#if THREAD_SDL_DEBUGF_ENABLED
|
|
|
|
#define THREAD_SDL_DEBUGF(...) DEBUGF(__VA_ARGS__)
|
2014-08-08 10:33:51 +00:00
|
|
|
static char __name[sizeof (((struct thread_debug_info *)0)->name)];
|
2007-09-08 12:20:53 +00:00
|
|
|
#define THREAD_SDL_GET_NAME(thread) \
|
2014-08-08 10:33:51 +00:00
|
|
|
({ format_thread_name(__name, sizeof (__name), thread); __name; })
|
2007-09-08 12:20:53 +00:00
|
|
|
#else
|
|
|
|
#define THREAD_SDL_DEBUGF(...)
|
|
|
|
#define THREAD_SDL_GET_NAME(thread)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define THREAD_PANICF(str...) \
|
|
|
|
({ fprintf(stderr, str); exit(-1); })
|
|
|
|
|
2007-09-10 03:49:12 +00:00
|
|
|
/* Jump buffers for graceful exit - kernel threads don't stay neatly
|
|
|
|
* in their start routines responding to messages so this is the only
|
|
|
|
* way to get them back in there so they may exit */
|
|
|
|
static jmp_buf thread_jmpbufs[MAXTHREADS];
|
2010-05-15 21:02:47 +00:00
|
|
|
/* this mutex locks out other Rockbox threads while one runs,
|
|
|
|
* that enables us to simulate a cooperative environment even if
|
|
|
|
* the host is preemptive */
|
2007-09-08 12:20:53 +00:00
|
|
|
static SDL_mutex *m;
|
2010-05-27 21:36:04 +00:00
|
|
|
#define THREADS_RUN 0
|
|
|
|
#define THREADS_EXIT 1
|
|
|
|
#define THREADS_EXIT_COMMAND_DONE 2
|
|
|
|
static volatile int threads_status = THREADS_RUN;
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2007-09-09 01:59:07 +00:00
|
|
|
extern long start_tick;
|
|
|
|
|
2010-05-15 21:02:47 +00:00
|
|
|
void sim_thread_shutdown(void)
|
2007-09-08 12:20:53 +00:00
|
|
|
{
|
|
|
|
int i;
|
2007-09-10 03:49:12 +00:00
|
|
|
|
2010-05-27 18:46:09 +00:00
|
|
|
/* This *has* to be a push operation from a thread not in the pool
|
|
|
|
so that they may be dislodged from their blocking calls. */
|
|
|
|
|
2007-09-10 03:49:12 +00:00
|
|
|
/* Tell all threads jump back to their start routines, unlock and exit
|
|
|
|
gracefully - we'll check each one in turn for it's status. Threads
|
2014-08-08 10:33:51 +00:00
|
|
|
_could_ terminate via thread_exit or multiple threads could exit
|
2007-09-10 03:49:12 +00:00
|
|
|
on each unlock but that is safe. */
|
2009-01-08 11:08:22 +00:00
|
|
|
|
|
|
|
/* Do this before trying to acquire lock */
|
2010-05-27 21:36:04 +00:00
|
|
|
threads_status = THREADS_EXIT;
|
2007-09-10 03:49:12 +00:00
|
|
|
|
2009-01-08 11:08:22 +00:00
|
|
|
/* Take control */
|
|
|
|
SDL_LockMutex(m);
|
|
|
|
|
2010-05-27 18:46:09 +00:00
|
|
|
/* Signal all threads on delay or block */
|
2007-09-08 12:20:53 +00:00
|
|
|
for (i = 0; i < MAXTHREADS; i++)
|
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *thread = __thread_slot_entry(i);
|
2010-05-27 18:46:09 +00:00
|
|
|
if (thread->context.s == NULL)
|
|
|
|
continue;
|
|
|
|
SDL_SemPost(thread->context.s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for all threads to finish and cleanup old ones. */
|
|
|
|
for (i = 0; i < MAXTHREADS; i++)
|
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *thread = __thread_slot_entry(i);
|
2010-05-27 18:46:09 +00:00
|
|
|
SDL_Thread *t = thread->context.t;
|
|
|
|
|
|
|
|
if (t != NULL)
|
2007-09-08 12:20:53 +00:00
|
|
|
{
|
2007-09-10 03:49:12 +00:00
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
/* Wait for it to finish */
|
|
|
|
SDL_WaitThread(t, NULL);
|
|
|
|
/* Relock for next thread signal */
|
2007-09-08 12:20:53 +00:00
|
|
|
SDL_LockMutex(m);
|
2010-05-27 18:46:09 +00:00
|
|
|
/* Already waited and exiting thread would have waited .told,
|
|
|
|
* replacing it with t. */
|
|
|
|
thread->context.told = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
/* Wait on any previous thread in this location-- could be one not
|
|
|
|
* quite finished exiting but has just unlocked the mutex. If it's
|
|
|
|
* NULL, the call returns immediately.
|
2010-05-27 18:46:09 +00:00
|
|
|
*
|
2014-08-08 10:33:51 +00:00
|
|
|
* See thread_exit below for more information. */
|
2010-05-27 18:46:09 +00:00
|
|
|
SDL_WaitThread(thread->context.told, NULL);
|
|
|
|
}
|
2007-09-08 12:20:53 +00:00
|
|
|
}
|
2007-09-10 03:49:12 +00:00
|
|
|
|
|
|
|
SDL_UnlockMutex(m);
|
2010-05-27 21:36:04 +00:00
|
|
|
|
|
|
|
/* Signal completion of operation */
|
|
|
|
threads_status = THREADS_EXIT_COMMAND_DONE;
|
2007-09-08 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
2010-05-15 21:02:47 +00:00
|
|
|
void sim_thread_exception_wait(void)
|
2009-01-08 11:08:22 +00:00
|
|
|
{
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
SDL_Delay(HZ/10);
|
2010-05-27 21:36:04 +00:00
|
|
|
if (threads_status != THREADS_RUN)
|
2009-01-08 11:08:22 +00:00
|
|
|
thread_exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-03 14:01:12 +00:00
|
|
|
/* A way to yield and leave the threading system for extended periods */
|
2010-05-15 21:02:47 +00:00
|
|
|
void sim_thread_lock(void *me)
|
2007-12-03 14:01:12 +00:00
|
|
|
{
|
|
|
|
SDL_LockMutex(m);
|
2014-08-08 10:33:51 +00:00
|
|
|
__running_self_entry() = (struct thread_entry *)me;
|
2007-12-03 14:01:12 +00:00
|
|
|
|
2010-05-27 21:36:04 +00:00
|
|
|
if (threads_status != THREADS_RUN)
|
2008-03-25 02:34:12 +00:00
|
|
|
thread_exit();
|
2007-12-03 14:01:12 +00:00
|
|
|
}
|
|
|
|
|
2010-05-15 21:02:47 +00:00
|
|
|
void * sim_thread_unlock(void)
|
2007-12-03 14:01:12 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *current = __running_self_entry();
|
2007-12-03 14:01:12 +00:00
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2008-03-25 02:34:12 +00:00
|
|
|
void switch_thread(void)
|
2007-09-08 12:20:53 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *current = __running_self_entry();
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2008-03-26 01:50:41 +00:00
|
|
|
enable_irq();
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2008-03-25 02:34:12 +00:00
|
|
|
switch (current->state)
|
|
|
|
{
|
|
|
|
case STATE_RUNNING:
|
|
|
|
{
|
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
/* Any other thread waiting already will get it first */
|
|
|
|
SDL_LockMutex(m);
|
|
|
|
break;
|
|
|
|
} /* STATE_RUNNING: */
|
|
|
|
|
|
|
|
case STATE_BLOCKED:
|
|
|
|
{
|
|
|
|
int oldlevel;
|
|
|
|
|
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
SDL_SemWait(current->context.s);
|
|
|
|
SDL_LockMutex(m);
|
|
|
|
|
2008-03-26 01:50:41 +00:00
|
|
|
oldlevel = disable_irq_save();
|
2008-03-25 02:34:12 +00:00
|
|
|
current->state = STATE_RUNNING;
|
2008-03-26 01:50:41 +00:00
|
|
|
restore_irq(oldlevel);
|
2008-03-25 02:34:12 +00:00
|
|
|
break;
|
|
|
|
} /* STATE_BLOCKED: */
|
|
|
|
|
|
|
|
case STATE_BLOCKED_W_TMO:
|
|
|
|
{
|
|
|
|
int result, oldlevel;
|
|
|
|
|
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
result = SDL_SemWaitTimeout(current->context.s, current->tmo_tick);
|
|
|
|
SDL_LockMutex(m);
|
|
|
|
|
2008-03-26 01:50:41 +00:00
|
|
|
oldlevel = disable_irq_save();
|
2008-03-25 02:34:12 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
current->state = STATE_RUNNING;
|
2007-09-10 03:49:12 +00:00
|
|
|
|
2008-03-25 02:34:12 +00:00
|
|
|
if (result == SDL_MUTEX_TIMEDOUT)
|
|
|
|
{
|
|
|
|
/* Other signals from an explicit wake could have been made before
|
|
|
|
* arriving here if we timed out waiting for the semaphore. Make
|
|
|
|
* sure the count is reset. */
|
|
|
|
while (SDL_SemValue(current->context.s) > 0)
|
|
|
|
SDL_SemTryWait(current->context.s);
|
|
|
|
}
|
|
|
|
|
2008-03-26 01:50:41 +00:00
|
|
|
restore_irq(oldlevel);
|
2008-03-25 02:34:12 +00:00
|
|
|
break;
|
|
|
|
} /* STATE_BLOCKED_W_TMO: */
|
|
|
|
|
|
|
|
case STATE_SLEEPING:
|
|
|
|
{
|
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
SDL_SemWaitTimeout(current->context.s, current->tmo_tick);
|
|
|
|
SDL_LockMutex(m);
|
|
|
|
current->state = STATE_RUNNING;
|
|
|
|
break;
|
|
|
|
} /* STATE_SLEEPING: */
|
|
|
|
}
|
|
|
|
|
2023-01-02 19:18:02 +00:00
|
|
|
#ifdef BUFLIB_DEBUG_CHECK_VALID
|
2014-01-09 20:37:07 +00:00
|
|
|
core_check_valid();
|
|
|
|
#endif
|
2014-08-08 10:33:51 +00:00
|
|
|
__running_self_entry() = current;
|
2008-03-25 02:34:12 +00:00
|
|
|
|
2010-05-27 21:36:04 +00:00
|
|
|
if (threads_status != THREADS_RUN)
|
2008-03-25 02:34:12 +00:00
|
|
|
thread_exit();
|
2007-09-08 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sleep_thread(int ticks)
|
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *current = __running_self_entry();
|
2007-09-09 01:59:07 +00:00
|
|
|
int rem;
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2007-10-16 01:25:17 +00:00
|
|
|
current->state = STATE_SLEEPING;
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2007-09-09 01:59:07 +00:00
|
|
|
rem = (SDL_GetTicks() - start_tick) % (1000/HZ);
|
|
|
|
if (rem < 0)
|
|
|
|
rem = 0;
|
|
|
|
|
2008-03-25 02:34:12 +00:00
|
|
|
current->tmo_tick = (1000/HZ) * ticks + ((1000/HZ)-1) - rem;
|
|
|
|
}
|
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
void block_thread_(struct thread_entry *current, int ticks)
|
2008-03-25 02:34:12 +00:00
|
|
|
{
|
2014-04-24 08:09:18 +00:00
|
|
|
if (ticks < 0)
|
|
|
|
current->state = STATE_BLOCKED;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
current->state = STATE_BLOCKED_W_TMO;
|
|
|
|
current->tmo_tick = (1000/HZ)*ticks;
|
|
|
|
}
|
2008-03-25 02:34:12 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
wait_queue_register(current);
|
2008-03-25 02:34:12 +00:00
|
|
|
}
|
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
unsigned int wakeup_thread_(struct thread_entry *thread)
|
2008-03-25 02:34:12 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
switch (thread->state)
|
2007-09-10 03:49:12 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
case STATE_BLOCKED:
|
|
|
|
case STATE_BLOCKED_W_TMO:
|
|
|
|
wait_queue_remove(thread);
|
|
|
|
thread->state = STATE_RUNNING;
|
|
|
|
SDL_SemPost(thread->context.s);
|
|
|
|
return THREAD_OK;
|
2007-09-10 03:49:12 +00:00
|
|
|
}
|
2008-03-25 02:34:12 +00:00
|
|
|
|
|
|
|
return THREAD_NONE;
|
|
|
|
}
|
|
|
|
|
2008-12-10 08:57:10 +00:00
|
|
|
void thread_thaw(unsigned int thread_id)
|
2008-03-25 02:34:12 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *thread = __thread_id_entry(thread_id);
|
2008-12-10 08:57:10 +00:00
|
|
|
|
|
|
|
if (thread->id == thread_id && thread->state == STATE_FROZEN)
|
2008-03-25 02:34:12 +00:00
|
|
|
{
|
|
|
|
thread->state = STATE_RUNNING;
|
|
|
|
SDL_SemPost(thread->context.s);
|
|
|
|
}
|
2006-02-03 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int runthread(void *data)
|
|
|
|
{
|
2007-09-08 12:20:53 +00:00
|
|
|
/* Cannot access thread variables before locking the mutex as the
|
|
|
|
data structures may not be filled-in yet. */
|
|
|
|
SDL_LockMutex(m);
|
2014-08-08 10:33:51 +00:00
|
|
|
|
|
|
|
struct thread_entry *current = (struct thread_entry *)data;
|
|
|
|
__running_self_entry() = current;
|
|
|
|
|
|
|
|
jmp_buf *current_jmpbuf = &thread_jmpbufs[THREAD_ID_SLOT(current->id)];
|
2007-09-10 03:49:12 +00:00
|
|
|
|
|
|
|
/* Setup jump for exit */
|
|
|
|
if (setjmp(*current_jmpbuf) == 0)
|
|
|
|
{
|
|
|
|
/* Run the thread routine */
|
2007-10-16 01:25:17 +00:00
|
|
|
if (current->state == STATE_FROZEN)
|
|
|
|
{
|
2008-03-25 02:34:12 +00:00
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
SDL_SemWait(current->context.s);
|
|
|
|
SDL_LockMutex(m);
|
2014-08-08 10:33:51 +00:00
|
|
|
__running_self_entry() = current;
|
2007-10-16 01:25:17 +00:00
|
|
|
}
|
|
|
|
|
2010-05-27 21:36:04 +00:00
|
|
|
if (threads_status == THREADS_RUN)
|
2007-10-16 01:25:17 +00:00
|
|
|
{
|
|
|
|
current->context.start();
|
|
|
|
THREAD_SDL_DEBUGF("Thread Done: %d (%s)\n",
|
2014-08-08 10:33:51 +00:00
|
|
|
THREAD_ID_SLOT(current->id),
|
|
|
|
THREAD_SDL_GET_NAME(current));
|
2007-10-16 01:25:17 +00:00
|
|
|
/* Thread routine returned - suicide */
|
|
|
|
}
|
|
|
|
|
2008-03-25 02:34:12 +00:00
|
|
|
thread_exit();
|
2007-09-10 03:49:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unlock and exit */
|
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
}
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2006-02-03 15:19:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-10 08:57:10 +00:00
|
|
|
unsigned int create_thread(void (*function)(void),
|
|
|
|
void* stack, size_t stack_size,
|
|
|
|
unsigned flags, const char *name)
|
2006-02-03 15:19:58 +00:00
|
|
|
{
|
2007-09-08 12:20:53 +00:00
|
|
|
THREAD_SDL_DEBUGF("Creating thread: (%s)\n", name ? name : "");
|
2006-02-03 15:19:58 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *thread = thread_alloc();
|
2008-03-25 02:34:12 +00:00
|
|
|
if (thread == NULL)
|
2007-09-08 12:20:53 +00:00
|
|
|
{
|
|
|
|
DEBUGF("Failed to find thread slot\n");
|
2008-12-10 08:57:10 +00:00
|
|
|
return 0;
|
2006-02-03 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
SDL_sem *s = SDL_CreateSemaphore(0);
|
2008-03-25 02:34:12 +00:00
|
|
|
if (s == NULL)
|
2007-09-08 12:20:53 +00:00
|
|
|
{
|
2008-03-25 02:34:12 +00:00
|
|
|
DEBUGF("Failed to create semaphore\n");
|
2008-12-10 08:57:10 +00:00
|
|
|
return 0;
|
2007-09-08 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
SDL_Thread *t = SDL_CreateThread(runthread, thread);
|
2007-09-08 12:20:53 +00:00
|
|
|
if (t == NULL)
|
|
|
|
{
|
|
|
|
DEBUGF("Failed to create SDL thread\n");
|
2008-03-25 02:34:12 +00:00
|
|
|
SDL_DestroySemaphore(s);
|
2008-12-10 08:57:10 +00:00
|
|
|
return 0;
|
2007-09-08 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
2008-03-25 02:34:12 +00:00
|
|
|
thread->name = name;
|
|
|
|
thread->state = (flags & CREATE_THREAD_FROZEN) ?
|
2007-10-16 01:25:17 +00:00
|
|
|
STATE_FROZEN : STATE_RUNNING;
|
2008-03-25 02:34:12 +00:00
|
|
|
thread->context.start = function;
|
|
|
|
thread->context.t = t;
|
|
|
|
thread->context.s = s;
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
THREAD_SDL_DEBUGF("New Thread: %lu (%s)\n",
|
|
|
|
(unsigned long)thread->id,
|
|
|
|
THREAD_SDL_GET_NAME(thread));
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2008-12-10 08:57:10 +00:00
|
|
|
return thread->id;
|
2014-08-08 10:33:51 +00:00
|
|
|
(void)stack; (void)stack_size;
|
2006-02-03 15:19:58 +00:00
|
|
|
}
|
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
void thread_exit(void)
|
2007-03-30 16:02:42 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *current = __running_self_entry();
|
2007-10-26 23:11:18 +00:00
|
|
|
|
2008-12-10 08:57:10 +00:00
|
|
|
int oldlevel = disable_irq_save();
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
SDL_Thread *t = current->context.t;
|
|
|
|
SDL_sem *s = current->context.s;
|
2010-05-27 18:46:09 +00:00
|
|
|
|
|
|
|
/* Wait the last thread here and keep this one or SDL will leak it since
|
|
|
|
* it doesn't free its own library allocations unless a wait is performed.
|
|
|
|
* Such behavior guards against the memory being invalid by the time
|
|
|
|
* SDL_WaitThread is reached and also against two different threads having
|
|
|
|
* the same pointer. It also makes SDL_WaitThread a non-concurrent function.
|
|
|
|
*
|
|
|
|
* However, see more below about SDL_KillThread.
|
|
|
|
*/
|
2014-08-08 10:33:51 +00:00
|
|
|
SDL_WaitThread(current->context.told, NULL);
|
2010-05-27 18:46:09 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
current->context.t = NULL;
|
|
|
|
current->context.s = NULL;
|
|
|
|
current->context.told = t;
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
unsigned int id = current->id;
|
|
|
|
new_thread_id(current);
|
|
|
|
current->state = STATE_KILLED;
|
|
|
|
wait_queue_wake(¤t->queue);
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2008-03-25 02:34:12 +00:00
|
|
|
SDL_DestroySemaphore(s);
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
/* Do a graceful exit - perform the longjmp back into the thread
|
|
|
|
function to return */
|
2008-03-26 01:50:41 +00:00
|
|
|
restore_irq(oldlevel);
|
2007-09-08 12:20:53 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
thread_free(current);
|
|
|
|
|
|
|
|
longjmp(thread_jmpbufs[THREAD_ID_SLOT(id)], 1);
|
|
|
|
|
2010-06-17 20:15:58 +00:00
|
|
|
/* This should never and must never be reached - if it is, the
|
|
|
|
* state is corrupted */
|
2011-03-05 17:48:06 +00:00
|
|
|
THREAD_PANICF("thread_exit->K:*R (ID: %d)", id);
|
2010-06-17 20:15:58 +00:00
|
|
|
while (1);
|
2008-03-25 02:34:12 +00:00
|
|
|
}
|
|
|
|
|
2008-12-10 08:57:10 +00:00
|
|
|
void thread_wait(unsigned int thread_id)
|
2007-10-16 01:25:17 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
struct thread_entry *current = __running_self_entry();
|
|
|
|
struct thread_entry *thread = __thread_id_entry(thread_id);
|
2008-03-25 02:34:12 +00:00
|
|
|
|
2011-03-05 17:48:06 +00:00
|
|
|
if (thread->id == thread_id && thread->state != STATE_KILLED)
|
2007-10-16 01:25:17 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
block_thread(current, TIMEOUT_BLOCK, &thread->queue);
|
2008-03-25 02:34:12 +00:00
|
|
|
switch_thread();
|
2007-10-16 01:25:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
/* Initialize SDL threading */
|
|
|
|
void init_threads(void)
|
2013-12-04 16:06:17 +00:00
|
|
|
{
|
2014-08-08 10:33:51 +00:00
|
|
|
m = SDL_CreateMutex();
|
2013-12-04 16:06:17 +00:00
|
|
|
|
2014-08-08 10:33:51 +00:00
|
|
|
if (SDL_LockMutex(m) == -1)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Couldn't lock mutex\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
thread_alloc_init();
|
|
|
|
|
|
|
|
struct thread_entry *thread = thread_alloc();
|
|
|
|
if (thread == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Main thread alloc failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Slot 0 is reserved for the main thread - initialize it here and
|
|
|
|
then create the SDL thread - it is possible to have a quick, early
|
|
|
|
shutdown try to access the structure. */
|
|
|
|
thread->name = __main_thread_name;
|
|
|
|
thread->state = STATE_RUNNING;
|
|
|
|
thread->context.s = SDL_CreateSemaphore(0);
|
|
|
|
thread->context.t = NULL; /* NULL for the implicit main thread */
|
|
|
|
__running_self_entry() = thread;
|
|
|
|
|
|
|
|
if (thread->context.s == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Failed to create main semaphore\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Tell all threads jump back to their start routines, unlock and exit
|
|
|
|
gracefully - we'll check each one in turn for it's status. Threads
|
|
|
|
_could_ terminate via thread_exit or multiple threads could exit
|
|
|
|
on each unlock but that is safe. */
|
|
|
|
|
|
|
|
/* Setup jump for exit */
|
|
|
|
if (setjmp(thread_jmpbufs[THREAD_ID_SLOT(thread->id)]) == 0)
|
|
|
|
{
|
|
|
|
THREAD_SDL_DEBUGF("Main Thread: %lu (%s)\n",
|
|
|
|
(unsigned long)thread->id,
|
|
|
|
THREAD_SDL_GET_NAME(thread));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_UnlockMutex(m);
|
|
|
|
|
|
|
|
/* Set to 'COMMAND_DONE' when other rockbox threads have exited. */
|
|
|
|
while (threads_status < THREADS_EXIT_COMMAND_DONE)
|
|
|
|
SDL_Delay(10);
|
|
|
|
|
|
|
|
SDL_DestroyMutex(m);
|
|
|
|
|
|
|
|
/* We're the main thead - perform exit - doesn't return. */
|
|
|
|
sim_do_exit();
|
2013-12-04 16:06:17 +00:00
|
|
|
}
|