We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 144 - Bug when freeing a timer (during mutex lock)
Summary: Bug when freeing a timer (during mutex lock)
Status: RESOLVED FIXED
Alias: None
Product: SDL
Classification: Unclassified
Component: timer (show other bugs)
Version: 1.2.9
Hardware: x86 Linux
: P2 blocker
Assignee: Sam Lantinga
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-02-16 11:25 UTC by Asfand Yar Qazi
Modified: 2018-07-24 22:29 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Asfand Yar Qazi 2006-02-16 11:25:41 UTC
Hi boys'n'girls (ok, so basically boys...)

I think there may be a bug when exclusive-locking a mutex when freeing a timer caused at the end of my application (I hope my terminology is correct - not too good at concurrency terminology, which is bad, because concurrency is teh futur.)

I'm using the RUDL game library (SDL based game library for Ruby) and when my application window terminates and goes off the screen, process doesn't actually end - (i.e. I don't go back to my shell prompt).  I have to manually terminate the process by pressing 'ctrl-c' (i.e. it hasn't crashed.)

This is a fully recreatable bug, it happens ALMOST every time (sometimes the process actually terminates successfully, which is wierd.)

Now, I've gdb'ed it while its in this non-terminated state, and here's some info (actually I used ddd but I've reproduced it using plain terminal mode gdb.)  The actual script I run is irrelevant - as long as the script makes a SDL timer, this happens.  By the way, this bug also happens exactly the same on SDL-1.2.8 as well as SDL-1.2.9.  Amazingly, it DIDN'T happen on a 2.4 kernel with GLIBC 2.2.5 (i.e. before NPTL).  Now I'm on the latest stable Gentoo.

Here's a dump of a GDB session where I've noticed some strange stuff going on (note stuff inbetween '<' and '>' is my editing):

$ gdb ../common/root/bin/ruby
GNU gdb 6.4
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) set args test/linktest.rb
(gdb) run
Starting program: <snip>/ruby test/linktest.rb
[Thread debugging using libthread_db enabled]
[New Thread -1210422624 (LWP 12988)]
(Init_RUDL())
(Starting video subsystem)
(Starting audio subsystem)
[New Thread -1217238096 (LWP 12991)]
(Starting timer subsystem)
[New Thread -1235706960 (LWP 12993)]
(Starting TTF)
(Reached RUDL_at_exit)
[Thread -1217238096 (zombie) exited]
(Stopping audio subsystem)
(Stopping video subsystem)
(Stopping TTF)
(Quitting the rest of it)
[Thread -1235706960 (zombie) exited]

<I PRESS CONTROL-C HERE>

Program received signal SIGINT, Interrupt.
[Switching to Thread -1210422624 (LWP 12988)]
0xffffe410 in __kernel_vsyscall ()
(gdb) backtrace
#0  0xffffe410 in __kernel_vsyscall ()
#1  0xb7f2117e in __lll_mutex_lock_wait () from /lib/tls/libpthread.so.0
#2  0xb7f1dfc7 in _L_mutex_lock_150 () from /lib/tls/libpthread.so.0
#3  0xb7f5bfd4 in ?? () from /lib/ld-linux.so.2
#4  0x08152fb0 in ?? ()
#5  0x00000001 in ?? ()
#6  0xbff575b0 in ?? ()
#7  0xb7f51542 in fixup () from /lib/ld-linux.so.2
#8  0xb7d39df6 in SDL_mutexP (mutex=0xfffffffc) at SDL_sysmutex.c:133
#9  0xb7d3a77e in SDL_RemoveTimer (id=0x826bdd8) at SDL_timer.c:221
#10 0xb7d5873d in freeEventTimer (freeMe=0xfffffffc) at rudl_timer.c:46
#11 0x08070eaa in rb_gc_call_finalizer_at_exit () at gc.c:1855
#12 0x08052e65 in ruby_finalize_1 () at eval.c:1488
#13 0x08066b73 in ruby_cleanup (ex=0) at eval.c:1523
#14 0x08066c31 in ruby_stop (ex=-4) at eval.c:1554
#15 0x08066c7f in ruby_run () at eval.c:1575
#16 0x080524e8 in main (argc=-4, argv=0xfffffffc, envp=0xbff578a0) at main.c:46
(gdb) frame 10
#10 0xb7d5873d in freeEventTimer (freeMe=0xfffffffc) at rudl_timer.c:46
46              SDL_RemoveTimer(freeMe);
(gdb) l
41      }
42
43      ///////////////////////////////// EVENTTIMER
44      void freeEventTimer(SDL_TimerID freeMe)
45      {
46              SDL_RemoveTimer(freeMe);
47      }
48
49      Uint32 timerCallback(Uint32 interval, void *param)
50      {
(gdb) frame 9
#9  0xb7d3a77e in SDL_RemoveTimer (id=0x826bdd8) at SDL_timer.c:221
221             SDL_mutexP(SDL_timer_mutex);
(gdb) l
216     {
217             SDL_TimerID t, prev = NULL;
218             SDL_bool removed;
219
220             removed = SDL_FALSE;
221             SDL_mutexP(SDL_timer_mutex);
222             /* Look for id in the linked list of timers */
223             for (t = SDL_timers; t; prev=t, t = t->next ) {
224                     if ( t == id ) {
225                             if(prev) {
(gdb) l 210
205             if ( ! SDL_timer_threaded ) {
206                     SDL_SetError("Multiple timers require threaded events!");
207                     return NULL;
208             }
209             SDL_mutexP(SDL_timer_mutex);
210             t = SDL_AddTimerInternal(interval, callback, param);
211             SDL_mutexV(SDL_timer_mutex);
212             return t;
213     }
214
(gdb)
215     SDL_bool SDL_RemoveTimer(SDL_TimerID id)
216     {
217             SDL_TimerID t, prev = NULL;
218             SDL_bool removed;
219
220             removed = SDL_FALSE;
221             SDL_mutexP(SDL_timer_mutex);
222             /* Look for id in the linked list of timers */
223             for (t = SDL_timers; t; prev=t, t = t->next ) {
224                     if ( t == id ) {
(gdb)
225                             if(prev) {
226                                     prev->next = t->next;
227                             } else {
228                                     SDL_timers = t->next;
229                             }
230                             free(t);
231                             --SDL_timer_running;
232                             removed = SDL_TRUE;
233                             list_changed = SDL_TRUE;
234                             break;
(gdb)
235                     }
236             }
237     #ifdef DEBUG_TIMERS
238             printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, SDL_timer_running, SDL_ThreadID());
239     #endif
240             SDL_mutexV(SDL_timer_mutex);
241             return removed;
242     }
243
244     /* Old style callback functions are wrapped through this */
(gdb) frame 8
#8  0xb7d39df6 in SDL_mutexP (mutex=0xfffffffc) at SDL_sysmutex.c:133
133             if ( pthread_mutex_lock(&mutex->id) < 0 ) {
(gdb) l
128                             SDL_SetError("pthread_mutex_lock() failed");
129                             retval = -1;
130                     }
131             }
132     #else
133             if ( pthread_mutex_lock(&mutex->id) < 0 ) {
134                     SDL_SetError("pthread_mutex_lock() failed");
135                     retval = -1;
136             }
137     #endif
(gdb) frame 9
#9  0xb7d3a77e in SDL_RemoveTimer (id=0x826bdd8) at SDL_timer.c:221
221             SDL_mutexP(SDL_timer_mutex);
(gdb) l
216     {
217             SDL_TimerID t, prev = NULL;
218             SDL_bool removed;
219
220             removed = SDL_FALSE;
221             SDL_mutexP(SDL_timer_mutex);
222             /* Look for id in the linked list of timers */
223             for (t = SDL_timers; t; prev=t, t = t->next ) {
224                     if ( t == id ) {
225                             if(prev) {
(gdb) print SDL_timer_mutex
$1 = (SDL_mutex *) 0x826a9d8
(gdb) frame 8
#8  0xb7d39df6 in SDL_mutexP (mutex=0xfffffffc) at SDL_sysmutex.c:133
133             if ( pthread_mutex_lock(&mutex->id) < 0 ) {
(gdb) l
128                             SDL_SetError("pthread_mutex_lock() failed");
129                             retval = -1;
130                     }
131             }
132     #else
133             if ( pthread_mutex_lock(&mutex->id) < 0 ) {
134                     SDL_SetError("pthread_mutex_lock() failed");
135                     retval = -1;
136             }
137     #endif
(gdb) print mutex
$2 = (SDL_mutex *) 0xfffffffc
(gdb) quit
The program is running.  Exit anyway? (y or n) y


Sorry if that's a bit long, I didn't want to leave anything out.

Ideas?
Comment 1 Sam Lantinga 2006-05-07 17:16:53 UTC
I'd like to get this fixed for SDL 1.2.10 release, if possible.
Comment 2 Sam Lantinga 2006-05-09 03:17:04 UTC
I believe this is now fixed in Subversion.  What was happening was a freed mutex was being waited on, after the timer subsystem had already been shut down.