The event filter and event watch functions are now thread-safe
authorSam Lantinga <slouken@libsdl.org>
Tue, 10 Oct 2017 17:41:41 -0700
changeset 115846d17410edb75
parent 11583 c48ab2c208a2
child 11585 9b646e8f4622
The event filter and event watch functions are now thread-safe
src/events/SDL_events.c
src/events/SDL_events_c.h
src/joystick/SDL_joystick.c
     1.1 --- a/src/events/SDL_events.c	Tue Oct 10 16:12:56 2017 -0400
     1.2 +++ b/src/events/SDL_events.c	Tue Oct 10 17:41:41 2017 -0700
     1.3 @@ -38,17 +38,15 @@
     1.4  /* An arbitrary limit so we don't have unbounded growth */
     1.5  #define SDL_MAX_QUEUED_EVENTS   65535
     1.6  
     1.7 -/* Public data -- the event filter */
     1.8 -SDL_EventFilter SDL_EventOK = NULL;
     1.9 -void *SDL_EventOKParam;
    1.10 -
    1.11  typedef struct SDL_EventWatcher {
    1.12      SDL_EventFilter callback;
    1.13      void *userdata;
    1.14 -    struct SDL_EventWatcher *next;
    1.15  } SDL_EventWatcher;
    1.16  
    1.17 +static SDL_mutex *SDL_event_watchers_lock;
    1.18 +static SDL_EventWatcher SDL_EventOK;
    1.19  static SDL_EventWatcher *SDL_event_watchers = NULL;
    1.20 +static int SDL_event_watchers_count = 0;
    1.21  
    1.22  typedef struct {
    1.23      Uint32 bits[8];
    1.24 @@ -367,12 +365,17 @@
    1.25          SDL_disabled_events[i] = NULL;
    1.26      }
    1.27  
    1.28 -    while (SDL_event_watchers) {
    1.29 -        SDL_EventWatcher *tmp = SDL_event_watchers;
    1.30 -        SDL_event_watchers = tmp->next;
    1.31 -        SDL_free(tmp);
    1.32 +    if (SDL_event_watchers_lock) {
    1.33 +        SDL_UnlockMutex(SDL_event_watchers_lock);
    1.34 +        SDL_DestroyMutex(SDL_event_watchers_lock);
    1.35 +        SDL_event_watchers_lock = NULL;
    1.36      }
    1.37 -    SDL_EventOK = NULL;
    1.38 +    if (SDL_event_watchers_count > 0) {
    1.39 +        SDL_free(SDL_event_watchers);
    1.40 +        SDL_event_watchers = NULL;
    1.41 +        SDL_event_watchers_count = 0;
    1.42 +    }
    1.43 +    SDL_zero(SDL_EventOK);
    1.44  
    1.45      if (SDL_EventQ.lock) {
    1.46          SDL_UnlockMutex(SDL_EventQ.lock);
    1.47 @@ -395,9 +398,16 @@
    1.48  #if !SDL_THREADS_DISABLED
    1.49      if (!SDL_EventQ.lock) {
    1.50          SDL_EventQ.lock = SDL_CreateMutex();
    1.51 +        if (SDL_EventQ.lock == NULL) {
    1.52 +            return -1;
    1.53 +        }
    1.54      }
    1.55 -    if (SDL_EventQ.lock == NULL) {
    1.56 -        return -1;
    1.57 +
    1.58 +    if (!SDL_event_watchers_lock) {
    1.59 +        SDL_event_watchers_lock = SDL_CreateMutex();
    1.60 +        if (SDL_event_watchers_lock == NULL) {
    1.61 +            return -1;
    1.62 +        }
    1.63      }
    1.64  #endif /* !SDL_THREADS_DISABLED */
    1.65  
    1.66 @@ -606,7 +616,7 @@
    1.67  #endif
    1.68  
    1.69      /* Lock the event queue */
    1.70 -    if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
    1.71 +    if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
    1.72          SDL_EventEntry *entry, *next;
    1.73          Uint32 type;
    1.74          for (entry = SDL_EventQ.head; entry; entry = next) {
    1.75 @@ -616,7 +626,9 @@
    1.76                  SDL_CutEvent(entry);
    1.77              }
    1.78          }
    1.79 -        SDL_UnlockMutex(SDL_EventQ.lock);
    1.80 +        if (SDL_EventQ.lock) {
    1.81 +            SDL_UnlockMutex(SDL_EventQ.lock);
    1.82 +        }
    1.83      }
    1.84  }
    1.85  
    1.86 @@ -688,16 +700,41 @@
    1.87  int
    1.88  SDL_PushEvent(SDL_Event * event)
    1.89  {
    1.90 -    SDL_EventWatcher *curr;
    1.91 -
    1.92      event->common.timestamp = SDL_GetTicks();
    1.93  
    1.94 -    if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
    1.95 -        return 0;
    1.96 -    }
    1.97 +    if (SDL_EventOK.callback || SDL_event_watchers_count != 0) {
    1.98 +        SDL_EventWatcher event_ok;
    1.99 +        SDL_EventWatcher *event_watchers = NULL;
   1.100 +        int i, event_watchers_count = 0;
   1.101  
   1.102 -    for (curr = SDL_event_watchers; curr; curr = curr->next) {
   1.103 -        curr->callback(curr->userdata, event);
   1.104 +        if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   1.105 +            event_ok = SDL_EventOK;
   1.106 +
   1.107 +            if (SDL_event_watchers_count > 0) {
   1.108 +                event_watchers = SDL_stack_alloc(SDL_EventWatcher, SDL_event_watchers_count);
   1.109 +                if (event_watchers) {
   1.110 +                    SDL_memcpy(event_watchers, SDL_event_watchers, SDL_event_watchers_count * sizeof(*event_watchers));
   1.111 +                    event_watchers_count = SDL_event_watchers_count;
   1.112 +                }
   1.113 +            }
   1.114 +
   1.115 +            if (SDL_event_watchers_lock) {
   1.116 +                SDL_UnlockMutex(SDL_event_watchers_lock);
   1.117 +            }
   1.118 +        } else {
   1.119 +            event_ok = SDL_EventOK;
   1.120 +        }
   1.121 +
   1.122 +        if (event_ok.callback && !event_ok.callback(event_ok.userdata, event)) {
   1.123 +            return 0;
   1.124 +        }
   1.125 +
   1.126 +        if (event_watchers_count > 0) {
   1.127 +            for (i = 0; i < event_watchers_count; ++i) {
   1.128 +                event_watchers[i].callback(event_watchers[i].userdata, event);
   1.129 +            }
   1.130 +            SDL_stack_free(event_watchers);
   1.131 +        }
   1.132      }
   1.133  
   1.134      if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
   1.135 @@ -712,69 +749,83 @@
   1.136  void
   1.137  SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
   1.138  {
   1.139 -    /* Set filter and discard pending events */
   1.140 -    SDL_EventOK = NULL;
   1.141 -    SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
   1.142 -    SDL_EventOKParam = userdata;
   1.143 -    SDL_EventOK = filter;
   1.144 +    if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   1.145 +        /* Set filter and discard pending events */
   1.146 +        SDL_EventOK.callback = filter;
   1.147 +        SDL_EventOK.userdata = userdata;
   1.148 +        SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
   1.149 +
   1.150 +        if (SDL_event_watchers_lock) {
   1.151 +            SDL_UnlockMutex(SDL_event_watchers_lock);
   1.152 +        }
   1.153 +    }
   1.154  }
   1.155  
   1.156  SDL_bool
   1.157  SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
   1.158  {
   1.159 +    SDL_EventWatcher event_ok;
   1.160 +
   1.161 +    if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   1.162 +        event_ok = SDL_EventOK;
   1.163 +
   1.164 +        if (SDL_event_watchers_lock) {
   1.165 +            SDL_UnlockMutex(SDL_event_watchers_lock);
   1.166 +        }
   1.167 +    } else {
   1.168 +        SDL_zero(event_ok);
   1.169 +    }
   1.170 +
   1.171      if (filter) {
   1.172 -        *filter = SDL_EventOK;
   1.173 +        *filter = event_ok.callback;
   1.174      }
   1.175      if (userdata) {
   1.176 -        *userdata = SDL_EventOKParam;
   1.177 +        *userdata = event_ok.userdata;
   1.178      }
   1.179 -    return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
   1.180 +    return event_ok.callback ? SDL_TRUE : SDL_FALSE;
   1.181  }
   1.182  
   1.183 -/* FIXME: This is not thread-safe yet */
   1.184  void
   1.185  SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
   1.186  {
   1.187 -    SDL_EventWatcher *watcher, *tail;
   1.188 +    if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   1.189 +        SDL_EventWatcher *event_watchers;
   1.190  
   1.191 -    watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
   1.192 -    if (!watcher) {
   1.193 -        /* Uh oh... */
   1.194 -        return;
   1.195 -    }
   1.196 +        event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(event_watchers));
   1.197 +        if (event_watchers) {
   1.198 +            SDL_EventWatcher *watcher;
   1.199  
   1.200 -    /* create the watcher */
   1.201 -    watcher->callback = filter;
   1.202 -    watcher->userdata = userdata;
   1.203 -    watcher->next = NULL;
   1.204 +            SDL_event_watchers = event_watchers;
   1.205 +            watcher = &SDL_event_watchers[SDL_event_watchers_count];
   1.206 +            watcher->callback = filter;
   1.207 +            watcher->userdata = userdata;
   1.208 +            ++SDL_event_watchers_count;
   1.209 +        }
   1.210  
   1.211 -    /* add the watcher to the end of the list */
   1.212 -    if (SDL_event_watchers) {
   1.213 -        for (tail = SDL_event_watchers; tail->next; tail = tail->next) {
   1.214 -            continue;
   1.215 +        if (SDL_event_watchers_lock) {
   1.216 +            SDL_UnlockMutex(SDL_event_watchers_lock);
   1.217          }
   1.218 -        tail->next = watcher;
   1.219 -    } else {
   1.220 -        SDL_event_watchers = watcher;
   1.221      }
   1.222  }
   1.223  
   1.224 -/* FIXME: This is not thread-safe yet */
   1.225  void
   1.226  SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
   1.227  {
   1.228 -    SDL_EventWatcher *prev = NULL;
   1.229 -    SDL_EventWatcher *curr;
   1.230 +    if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
   1.231 +        int i;
   1.232  
   1.233 -    for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
   1.234 -        if (curr->callback == filter && curr->userdata == userdata) {
   1.235 -            if (prev) {
   1.236 -                prev->next = curr->next;
   1.237 -            } else {
   1.238 -                SDL_event_watchers = curr->next;
   1.239 +        for (i = 0; i < SDL_event_watchers_count; ++i) {
   1.240 +            if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) {
   1.241 +                --SDL_event_watchers_count;
   1.242 +                if (i < SDL_event_watchers_count) {
   1.243 +                    SDL_memcpy(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
   1.244 +                }
   1.245 +                break;
   1.246              }
   1.247 -            SDL_free(curr);
   1.248 -            break;
   1.249 +        }
   1.250 +
   1.251 +        if (SDL_event_watchers_lock) {
   1.252 +            SDL_UnlockMutex(SDL_event_watchers_lock);
   1.253          }
   1.254      }
   1.255  }
   1.256 @@ -782,7 +833,7 @@
   1.257  void
   1.258  SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
   1.259  {
   1.260 -    if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
   1.261 +    if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
   1.262          SDL_EventEntry *entry, *next;
   1.263          for (entry = SDL_EventQ.head; entry; entry = next) {
   1.264              next = entry->next;
   1.265 @@ -790,7 +841,9 @@
   1.266                  SDL_CutEvent(entry);
   1.267              }
   1.268          }
   1.269 -        SDL_UnlockMutex(SDL_EventQ.lock);
   1.270 +        if (SDL_EventQ.lock) {
   1.271 +            SDL_UnlockMutex(SDL_EventQ.lock);
   1.272 +        }
   1.273      }
   1.274  }
   1.275  
     2.1 --- a/src/events/SDL_events_c.h	Tue Oct 10 16:12:56 2017 -0400
     2.2 +++ b/src/events/SDL_events_c.h	Tue Oct 10 17:41:41 2017 -0700
     2.3 @@ -46,8 +46,4 @@
     2.4  
     2.5  extern void SDL_SendPendingQuit(void);
     2.6  
     2.7 -/* The event filter function */
     2.8 -extern SDL_EventFilter SDL_EventOK;
     2.9 -extern void *SDL_EventOKParam;
    2.10 -
    2.11  /* vi: set ts=4 sw=4 expandtab: */
     3.1 --- a/src/joystick/SDL_joystick.c	Tue Oct 10 16:12:56 2017 -0400
     3.2 +++ b/src/joystick/SDL_joystick.c	Tue Oct 10 17:41:41 2017 -0700
     3.3 @@ -601,10 +601,7 @@
     3.4  
     3.5      if (SDL_GetEventState(event.type) == SDL_ENABLE) {
     3.6          event.jdevice.which = device_index;
     3.7 -        if ((SDL_EventOK == NULL) ||
     3.8 -             (*SDL_EventOK) (SDL_EventOKParam, &event)) {
     3.9 -            SDL_PushEvent(&event);
    3.10 -        }
    3.11 +        SDL_PushEvent(&event);
    3.12      }
    3.13  #endif /* !SDL_EVENTS_DISABLED */
    3.14  }
    3.15 @@ -647,10 +644,7 @@
    3.16  
    3.17      if (SDL_GetEventState(event.type) == SDL_ENABLE) {
    3.18          event.jdevice.which = device_instance;
    3.19 -        if ((SDL_EventOK == NULL) ||
    3.20 -             (*SDL_EventOK) (SDL_EventOKParam, &event)) {
    3.21 -            SDL_PushEvent(&event);
    3.22 -        }
    3.23 +        SDL_PushEvent(&event);
    3.24      }
    3.25  
    3.26      UpdateEventsForDeviceRemoval();