src/thread/amigaos/SDL_thread.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
permissions -rw-r--r--
more tweaking indent options
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
/* System independent thread management routines for SDL */
slouken@0
    25
slouken@0
    26
#include "SDL_mutex.h"
slouken@0
    27
#include "SDL_thread.h"
slouken@1361
    28
#include "../SDL_thread_c.h"
slouken@1361
    29
#include "../SDL_systhread.h"
slouken@0
    30
slouken@0
    31
#define ARRAY_CHUNKSIZE	32
slouken@0
    32
/* The array of threads currently active in the application
slouken@0
    33
   (except the main thread)
slouken@0
    34
   The manipulation of an array here is safer than using a linked list.
slouken@0
    35
*/
slouken@0
    36
static int SDL_maxthreads = 0;
slouken@0
    37
static int SDL_numthreads = 0;
slouken@0
    38
static SDL_Thread **SDL_Threads = NULL;
slouken@0
    39
static struct SignalSemaphore thread_lock;
slouken@0
    40
int thread_lock_created = 0;
slouken@0
    41
slouken@1662
    42
int
slouken@1668
    43
SDL_ThreadsInit(void)
slouken@0
    44
{
slouken@1668
    45
    InitSemaphore(&thread_lock);
slouken@1662
    46
    thread_lock_created = 1;
slouken@1662
    47
    return 0;
slouken@0
    48
}
slouken@0
    49
slouken@0
    50
/* This should never be called...
slouken@0
    51
   If this is called by SDL_Quit(), we don't know whether or not we should
slouken@0
    52
   clean up threads here.  If any threads are still running after this call,
slouken@0
    53
   they will no longer have access to any per-thread data.
slouken@0
    54
 */
slouken@1662
    55
void
slouken@1668
    56
SDL_ThreadsQuit()
slouken@0
    57
{
slouken@1662
    58
    thread_lock_created = 0;
slouken@0
    59
}
slouken@0
    60
slouken@0
    61
/* Routines for manipulating the thread list */
slouken@1662
    62
static void
slouken@1668
    63
SDL_AddThread(SDL_Thread * thread)
slouken@0
    64
{
slouken@1662
    65
    SDL_Thread **threads;
slouken@0
    66
slouken@1662
    67
    /* WARNING:
slouken@1662
    68
       If the very first threads are created simultaneously, then
slouken@1662
    69
       there could be a race condition causing memory corruption.
slouken@1662
    70
       In practice, this isn't a problem because by definition there
slouken@1662
    71
       is only one thread running the first time this is called.
slouken@1662
    72
     */
slouken@1662
    73
    if (!thread_lock_created) {
slouken@1668
    74
        if (SDL_ThreadsInit() < 0) {
slouken@1662
    75
            return;
slouken@1662
    76
        }
slouken@1662
    77
    }
slouken@1668
    78
    ObtainSemaphore(&thread_lock);
slouken@0
    79
slouken@1662
    80
    /* Expand the list of threads, if necessary */
slouken@0
    81
#ifdef DEBUG_THREADS
slouken@1668
    82
    printf("Adding thread (%d already - %d max)\n",
slouken@1668
    83
           SDL_numthreads, SDL_maxthreads);
slouken@0
    84
#endif
slouken@1662
    85
    if (SDL_numthreads == SDL_maxthreads) {
slouken@1662
    86
        threads =
slouken@1668
    87
            (SDL_Thread **) SDL_malloc((SDL_maxthreads + ARRAY_CHUNKSIZE) *
slouken@1668
    88
                                       (sizeof *threads));
slouken@1662
    89
        if (threads == NULL) {
slouken@1668
    90
            SDL_OutOfMemory();
slouken@1662
    91
            goto done;
slouken@1662
    92
        }
slouken@1668
    93
        SDL_memcpy(threads, SDL_Threads, SDL_numthreads * (sizeof *threads));
slouken@1662
    94
        SDL_maxthreads += ARRAY_CHUNKSIZE;
slouken@1662
    95
        if (SDL_Threads) {
slouken@1668
    96
            SDL_free(SDL_Threads);
slouken@1662
    97
        }
slouken@1662
    98
        SDL_Threads = threads;
slouken@1662
    99
    }
slouken@1662
   100
    SDL_Threads[SDL_numthreads++] = thread;
slouken@1662
   101
  done:
slouken@1668
   102
    ReleaseSemaphore(&thread_lock);
slouken@0
   103
}
slouken@0
   104
slouken@1662
   105
static void
slouken@1668
   106
SDL_DelThread(SDL_Thread * thread)
slouken@0
   107
{
slouken@1662
   108
    int i;
slouken@0
   109
slouken@1662
   110
    if (thread_lock_created) {
slouken@1668
   111
        ObtainSemaphore(&thread_lock);
slouken@1662
   112
        for (i = 0; i < SDL_numthreads; ++i) {
slouken@1662
   113
            if (thread == SDL_Threads[i]) {
slouken@1662
   114
                break;
slouken@1662
   115
            }
slouken@1662
   116
        }
slouken@1662
   117
        if (i < SDL_numthreads) {
slouken@1662
   118
            --SDL_numthreads;
slouken@1662
   119
            while (i < SDL_numthreads) {
slouken@1662
   120
                SDL_Threads[i] = SDL_Threads[i + 1];
slouken@1662
   121
                ++i;
slouken@1662
   122
            }
slouken@0
   123
#ifdef DEBUG_THREADS
slouken@1668
   124
            printf("Deleting thread (%d left - %d max)\n",
slouken@1668
   125
                   SDL_numthreads, SDL_maxthreads);
slouken@0
   126
#endif
slouken@1662
   127
        }
slouken@1668
   128
        ReleaseSemaphore(&thread_lock);
slouken@1662
   129
    }
slouken@0
   130
}
slouken@0
   131
slouken@0
   132
/* The default (non-thread-safe) global error variable */
slouken@0
   133
static SDL_error SDL_global_error;
slouken@0
   134
slouken@0
   135
/* Routine to get the thread-specific error variable */
slouken@1662
   136
SDL_error *
slouken@1668
   137
SDL_GetErrBuf(void)
slouken@0
   138
{
slouken@1662
   139
    SDL_error *errbuf;
slouken@0
   140
slouken@1662
   141
    errbuf = &SDL_global_error;
slouken@1662
   142
    if (SDL_Threads) {
slouken@1662
   143
        int i;
slouken@1662
   144
        Uint32 this_thread;
slouken@0
   145
slouken@1668
   146
        this_thread = SDL_ThreadID();
slouken@1668
   147
        ObtainSemaphore(&thread_lock);
slouken@1662
   148
        for (i = 0; i < SDL_numthreads; ++i) {
slouken@1662
   149
            if (this_thread == SDL_Threads[i]->threadid) {
slouken@1662
   150
                errbuf = &SDL_Threads[i]->errbuf;
slouken@1662
   151
                break;
slouken@1662
   152
            }
slouken@1662
   153
        }
slouken@1668
   154
        ReleaseSemaphore(&thread_lock);
slouken@1662
   155
    }
slouken@1662
   156
    return (errbuf);
slouken@0
   157
}
slouken@0
   158
slouken@0
   159
slouken@0
   160
/* Arguments and callback to setup and run the user thread function */
slouken@1662
   161
typedef struct
slouken@1662
   162
{
slouken@1662
   163
    int (*func) (void *);
slouken@1662
   164
    void *data;
slouken@1662
   165
    SDL_Thread *info;
slouken@1662
   166
    struct Task *wait;
slouken@0
   167
} thread_args;
slouken@0
   168
slouken@1662
   169
void
slouken@1668
   170
SDL_RunThread(void *data)
slouken@0
   171
{
slouken@1662
   172
    thread_args *args;
slouken@1662
   173
    int (*userfunc) (void *);
slouken@1662
   174
    void *userdata;
slouken@1662
   175
    int *statusloc;
slouken@0
   176
slouken@1662
   177
    /* Perform any system-dependent setup
slouken@1662
   178
       - this function cannot fail, and cannot use SDL_SetError()
slouken@1662
   179
     */
slouken@1668
   180
    SDL_SYS_SetupThread();
slouken@0
   181
slouken@1662
   182
    /* Get the thread id */
slouken@1662
   183
    args = (thread_args *) data;
slouken@1668
   184
    args->info->threadid = SDL_ThreadID();
slouken@0
   185
slouken@1662
   186
    /* Figure out what function to run */
slouken@1662
   187
    userfunc = args->func;
slouken@1662
   188
    userdata = args->data;
slouken@1662
   189
    statusloc = &args->info->status;
slouken@0
   190
slouken@1662
   191
    /* Wake up the parent thread */
slouken@1668
   192
    Signal(args->wait, SIGBREAKF_CTRL_E);
slouken@0
   193
slouken@1662
   194
    /* Run the function */
slouken@1668
   195
    *statusloc = userfunc(userdata);
slouken@0
   196
}
slouken@0
   197
slouken@1662
   198
SDL_Thread *
slouken@1668
   199
SDL_CreateThread(int (*fn) (void *), void *data)
slouken@0
   200
{
slouken@1662
   201
    SDL_Thread *thread;
slouken@1662
   202
    thread_args *args;
slouken@1662
   203
    int ret;
slouken@0
   204
slouken@1662
   205
    /* Allocate memory for the thread info structure */
slouken@1668
   206
    thread = (SDL_Thread *) SDL_malloc(sizeof(*thread));
slouken@1662
   207
    if (thread == NULL) {
slouken@1668
   208
        SDL_OutOfMemory();
slouken@1662
   209
        return (NULL);
slouken@1662
   210
    }
slouken@1668
   211
    SDL_memset(thread, 0, (sizeof *thread));
slouken@1662
   212
    thread->status = -1;
slouken@0
   213
slouken@1662
   214
    /* Set up the arguments for the thread */
slouken@1668
   215
    args = (thread_args *) SDL_malloc(sizeof(*args));
slouken@1662
   216
    if (args == NULL) {
slouken@1668
   217
        SDL_OutOfMemory();
slouken@1668
   218
        SDL_free(thread);
slouken@1662
   219
        return (NULL);
slouken@1662
   220
    }
slouken@1662
   221
    args->func = fn;
slouken@1662
   222
    args->data = data;
slouken@1662
   223
    args->info = thread;
slouken@1668
   224
    args->wait = FindTask(NULL);
slouken@1662
   225
    if (args->wait == NULL) {
slouken@1668
   226
        SDL_free(thread);
slouken@1668
   227
        SDL_free(args);
slouken@1668
   228
        SDL_OutOfMemory();
slouken@1662
   229
        return (NULL);
slouken@1662
   230
    }
slouken@0
   231
slouken@1662
   232
    /* Add the thread to the list of available threads */
slouken@1668
   233
    SDL_AddThread(thread);
slouken@0
   234
slouken@1668
   235
    D(bug("Starting thread...\n"));
slouken@0
   236
slouken@1662
   237
    /* Create the thread and go! */
slouken@1668
   238
    ret = SDL_SYS_CreateThread(thread, args);
slouken@1662
   239
    if (ret >= 0) {
slouken@1668
   240
        D(bug("Waiting for thread CTRL_E...\n"));
slouken@1662
   241
        /* Wait for the thread function to use arguments */
slouken@1668
   242
        Wait(SIGBREAKF_CTRL_E);
slouken@1668
   243
        D(bug("  Arrived."));
slouken@1662
   244
    } else {
slouken@1662
   245
        /* Oops, failed.  Gotta free everything */
slouken@1668
   246
        SDL_DelThread(thread);
slouken@1668
   247
        SDL_free(thread);
slouken@1662
   248
        thread = NULL;
slouken@1662
   249
    }
slouken@1668
   250
    SDL_free(args);
slouken@0
   251
slouken@1662
   252
    /* Everything is running now */
slouken@1662
   253
    return (thread);
slouken@0
   254
}
slouken@0
   255
slouken@1662
   256
void
slouken@1668
   257
SDL_WaitThread(SDL_Thread * thread, int *status)
slouken@0
   258
{
slouken@1662
   259
    if (thread) {
slouken@1668
   260
        SDL_SYS_WaitThread(thread);
slouken@1662
   261
        if (status) {
slouken@1662
   262
            *status = thread->status;
slouken@1662
   263
        }
slouken@1668
   264
        SDL_DelThread(thread);
slouken@1668
   265
        SDL_free(thread);
slouken@1662
   266
    }
slouken@0
   267
}
slouken@0
   268
slouken@1662
   269
Uint32
slouken@1668
   270
SDL_GetThreadID(SDL_Thread * thread)
slouken@21
   271
{
slouken@1662
   272
    Uint32 id;
slouken@21
   273
slouken@1662
   274
    if (thread) {
slouken@1662
   275
        id = thread->threadid;
slouken@1662
   276
    } else {
slouken@1668
   277
        id = SDL_ThreadID();
slouken@1662
   278
    }
slouken@1662
   279
    return (id);
slouken@21
   280
}
slouken@21
   281
slouken@1662
   282
void
slouken@1668
   283
SDL_KillThread(SDL_Thread * thread)
slouken@0
   284
{
slouken@1662
   285
    if (thread) {
slouken@1668
   286
        SDL_SYS_KillThread(thread);
slouken@1668
   287
        SDL_WaitThread(thread, NULL);
slouken@1662
   288
    }
slouken@0
   289
}
slouken@0
   290
slouken@1662
   291
/* vi: set ts=4 sw=4 expandtab: */