Mercurial > sdl-ios-xcode
annotate src/thread/amigaos/SDL_thread.c @ 765:4c2ba6161939
Editors Note: The original patch was modified to use SDL_Delay() instead of
nanosleep because nanosleep may not be portable to all systems
using SDL with the ALSA backend. This may be a moot point with
the switch to blocking writes anyway...
Date: Sat, 27 Dec 2003 21:47:36 +0100
From: Michel Daenzer
To: Debian Bug Tracking System
Subject: [SDL] Bug#225252: [PATCH] ALSA fixes
Package: libsdl1.2debian-all
Version: 1.2.6-2
Severity: normal
Tags: patch
For SDL 1.2.6, the ALSA backend was changed to call snd_pcm_open() with
SND_PCM_NONBLOCK. That's a good idea per se, however, it causes high CPU
usage, interrupted sound and stuttering in some games here. Taking a nanosleep
whenever snd_pcm_writei() returns -EAGAIN fixes this, but I think it's more
efficient to use blocking mode for the actual sound playback. Feedback from the
SDL and ALSA lists appreciated.
The patch also fixes the default ALSA device to be used.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 04 Jan 2004 15:40:50 +0000 |
parents | f6ffac90895c |
children | b8d311d90021 |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
297
f6ffac90895c
Updated copyright information for 2002
Sam Lantinga <slouken@libsdl.org>
parents:
252
diff
changeset
|
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
21
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 /* System independent thread management routines for SDL */ | |
29 | |
30 #include <stdio.h> | |
31 #include <stdlib.h> | |
32 #include <string.h> | |
33 | |
34 #include "SDL_error.h" | |
35 #include "SDL_mutex.h" | |
36 #include "SDL_thread.h" | |
37 #include "SDL_thread_c.h" | |
38 #include "SDL_systhread.h" | |
39 | |
40 #define ARRAY_CHUNKSIZE 32 | |
41 /* The array of threads currently active in the application | |
42 (except the main thread) | |
43 The manipulation of an array here is safer than using a linked list. | |
44 */ | |
45 static int SDL_maxthreads = 0; | |
46 static int SDL_numthreads = 0; | |
47 static SDL_Thread **SDL_Threads = NULL; | |
48 static struct SignalSemaphore thread_lock; | |
49 int thread_lock_created = 0; | |
50 | |
51 int SDL_ThreadsInit(void) | |
52 { | |
53 InitSemaphore(&thread_lock); | |
54 thread_lock_created=1; | |
55 return 0; | |
56 } | |
57 | |
58 /* This should never be called... | |
59 If this is called by SDL_Quit(), we don't know whether or not we should | |
60 clean up threads here. If any threads are still running after this call, | |
61 they will no longer have access to any per-thread data. | |
62 */ | |
63 void SDL_ThreadsQuit() | |
64 { | |
65 thread_lock_created=0; | |
66 } | |
67 | |
68 /* Routines for manipulating the thread list */ | |
69 static void SDL_AddThread(SDL_Thread *thread) | |
70 { | |
71 SDL_Thread **threads; | |
72 | |
73 /* WARNING: | |
74 If the very first threads are created simultaneously, then | |
75 there could be a race condition causing memory corruption. | |
76 In practice, this isn't a problem because by definition there | |
77 is only one thread running the first time this is called. | |
78 */ | |
79 if ( !thread_lock_created ) { | |
80 if ( SDL_ThreadsInit() < 0 ) { | |
81 return; | |
82 } | |
83 } | |
84 ObtainSemaphore(&thread_lock); | |
85 | |
86 /* Expand the list of threads, if necessary */ | |
87 #ifdef DEBUG_THREADS | |
88 printf("Adding thread (%d already - %d max)\n", | |
89 SDL_numthreads, SDL_maxthreads); | |
90 #endif | |
91 if ( SDL_numthreads == SDL_maxthreads ) { | |
92 threads=(SDL_Thread **)malloc((SDL_maxthreads+ARRAY_CHUNKSIZE)* | |
93 (sizeof *threads)); | |
94 if ( threads == NULL ) { | |
95 SDL_OutOfMemory(); | |
96 goto done; | |
97 } | |
98 memcpy(threads, SDL_Threads, SDL_numthreads*(sizeof *threads)); | |
99 SDL_maxthreads += ARRAY_CHUNKSIZE; | |
100 if ( SDL_Threads ) { | |
101 free(SDL_Threads); | |
102 } | |
103 SDL_Threads = threads; | |
104 } | |
105 SDL_Threads[SDL_numthreads++] = thread; | |
106 done: | |
107 ReleaseSemaphore(&thread_lock); | |
108 } | |
109 | |
110 static void SDL_DelThread(SDL_Thread *thread) | |
111 { | |
112 int i; | |
113 | |
114 if ( thread_lock_created ) { | |
115 ObtainSemaphore(&thread_lock); | |
116 for ( i=0; i<SDL_numthreads; ++i ) { | |
117 if ( thread == SDL_Threads[i] ) { | |
118 break; | |
119 } | |
120 } | |
121 if ( i < SDL_numthreads ) { | |
122 --SDL_numthreads; | |
123 while ( i < SDL_numthreads ) { | |
124 SDL_Threads[i] = SDL_Threads[i+1]; | |
125 ++i; | |
126 } | |
127 #ifdef DEBUG_THREADS | |
128 printf("Deleting thread (%d left - %d max)\n", | |
129 SDL_numthreads, SDL_maxthreads); | |
130 #endif | |
131 } | |
132 ReleaseSemaphore(&thread_lock); | |
133 } | |
134 } | |
135 | |
136 /* The default (non-thread-safe) global error variable */ | |
137 static SDL_error SDL_global_error; | |
138 | |
139 /* Routine to get the thread-specific error variable */ | |
140 SDL_error *SDL_GetErrBuf(void) | |
141 { | |
142 SDL_error *errbuf; | |
143 | |
144 errbuf = &SDL_global_error; | |
145 if ( SDL_Threads ) { | |
146 int i; | |
147 Uint32 this_thread; | |
148 | |
149 this_thread = SDL_ThreadID(); | |
150 ObtainSemaphore(&thread_lock); | |
151 for ( i=0; i<SDL_numthreads; ++i ) { | |
152 if ( this_thread == SDL_Threads[i]->threadid ) { | |
153 errbuf = &SDL_Threads[i]->errbuf; | |
154 break; | |
155 } | |
156 } | |
157 ReleaseSemaphore(&thread_lock); | |
158 } | |
159 return(errbuf); | |
160 } | |
161 | |
162 | |
163 /* Arguments and callback to setup and run the user thread function */ | |
164 typedef struct { | |
165 int (*func)(void *); | |
166 void *data; | |
167 SDL_Thread *info; | |
168 struct Task *wait; | |
169 } thread_args; | |
170 | |
171 void SDL_RunThread(void *data) | |
172 { | |
173 thread_args *args; | |
174 int (*userfunc)(void *); | |
175 void *userdata; | |
176 int *statusloc; | |
177 | |
178 /* Perform any system-dependent setup | |
179 - this function cannot fail, and cannot use SDL_SetError() | |
180 */ | |
181 SDL_SYS_SetupThread(); | |
182 | |
183 /* Get the thread id */ | |
184 args = (thread_args *)data; | |
185 args->info->threadid = SDL_ThreadID(); | |
186 | |
187 /* Figure out what function to run */ | |
188 userfunc = args->func; | |
189 userdata = args->data; | |
190 statusloc = &args->info->status; | |
191 | |
192 /* Wake up the parent thread */ | |
193 Signal(args->wait,SIGBREAKF_CTRL_E); | |
194 | |
195 /* Run the function */ | |
196 *statusloc = userfunc(userdata); | |
197 } | |
198 | |
199 SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data) | |
200 { | |
201 SDL_Thread *thread; | |
202 thread_args *args; | |
203 int ret; | |
204 | |
205 /* Allocate memory for the thread info structure */ | |
206 thread = (SDL_Thread *)malloc(sizeof(*thread)); | |
207 if ( thread == NULL ) { | |
208 SDL_OutOfMemory(); | |
209 return(NULL); | |
210 } | |
211 memset(thread, 0, (sizeof *thread)); | |
212 thread->status = -1; | |
213 | |
214 /* Set up the arguments for the thread */ | |
215 args = (thread_args *)malloc(sizeof(*args)); | |
216 if ( args == NULL ) { | |
217 SDL_OutOfMemory(); | |
218 free(thread); | |
219 return(NULL); | |
220 } | |
221 args->func = fn; | |
222 args->data = data; | |
223 args->info = thread; | |
224 args->wait = FindTask(NULL); | |
225 if ( args->wait == NULL ) { | |
226 free(thread); | |
227 free(args); | |
228 SDL_OutOfMemory(); | |
229 return(NULL); | |
230 } | |
231 | |
232 /* Add the thread to the list of available threads */ | |
233 SDL_AddThread(thread); | |
234 | |
235 D(bug("Starting thread...\n")); | |
236 | |
237 /* Create the thread and go! */ | |
238 ret = SDL_SYS_CreateThread(thread, args); | |
239 if ( ret >= 0 ) { | |
240 D(bug("Waiting for thread CTRL_E...\n")); | |
241 /* Wait for the thread function to use arguments */ | |
242 Wait(SIGBREAKF_CTRL_E); | |
243 D(bug(" Arrived.")); | |
244 } else { | |
245 /* Oops, failed. Gotta free everything */ | |
246 SDL_DelThread(thread); | |
247 free(thread); | |
248 thread = NULL; | |
249 } | |
250 free(args); | |
251 | |
252 /* Everything is running now */ | |
253 return(thread); | |
254 } | |
255 | |
256 void SDL_WaitThread(SDL_Thread *thread, int *status) | |
257 { | |
258 if ( thread ) { | |
259 SDL_SYS_WaitThread(thread); | |
260 if ( status ) { | |
261 *status = thread->status; | |
262 } | |
263 SDL_DelThread(thread); | |
264 free(thread); | |
265 } | |
266 } | |
267 | |
21
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
268 Uint32 SDL_GetThreadID(SDL_Thread *thread) |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
269 { |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
270 Uint32 id; |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
271 |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
272 if ( thread ) { |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
273 id = thread->threadid; |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
274 } else { |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
275 id = SDL_ThreadID(); |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
276 } |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
277 return(id); |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
278 } |
75a95f82bc1f
Updated the Amiga OS port of SDL (thanks Gabriele)
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
279 |
0 | 280 void SDL_KillThread(SDL_Thread *thread) |
281 { | |
282 if ( thread ) { | |
283 SDL_SYS_KillThread(thread); | |
284 SDL_WaitThread(thread, NULL); | |
285 } | |
286 } | |
287 |