Simple Directmedia Layer

Removed external hashtable locking functions

Read-write locks are not recursive and can't be upgraded from one type to another, so it's not safe to lock the hash table and then call functions that operate on it. If you really want this functionality, we'd need to create unlocked versions of the hashtable functions and you would call those once you've taken a lock on the hashtable, and we'd have to assert that the operations you're doing are compatible with the type of lock you've taken.

All of that complicates working with hashtables, so if you need that type of access, you should probably just use external locking.

Changed files
+71 -56
src
-22
src/SDL_hashtable.c
··· 493 493 return !(table && table->num_occupied_slots); 494 494 } 495 495 496 - void SDL_LockHashTable(SDL_HashTable *table, bool for_writing) 497 - { 498 - if (!table) { 499 - return; 500 - } 501 - 502 - if (for_writing) { 503 - SDL_LockRWLockForWriting(table->lock); 504 - } else { 505 - SDL_LockRWLockForReading(table->lock); 506 - } 507 - } 508 - 509 - void SDL_UnlockHashTable(SDL_HashTable *table) 510 - { 511 - if (!table) { 512 - return; 513 - } 514 - 515 - SDL_UnlockRWLock(table->lock); 516 - } 517 - 518 496 static void nuke_all(SDL_HashTable *table) 519 497 { 520 498 void *data = table->data;
+2 -5
src/SDL_hashtable.h
··· 55 55 // This function is thread-safe if the hashtable was created with threadsafe = true 56 56 extern bool SDL_HashTableEmpty(SDL_HashTable *table); 57 57 58 - extern void SDL_LockHashTable(SDL_HashTable *table, bool for_writing); 59 - extern void SDL_UnlockHashTable(SDL_HashTable *table); 60 - 61 58 // iterate all values for a specific key. This only makes sense if the hash is stackable. If not-stackable, just use SDL_FindInHashTable(). 62 - // This function is not thread-safe, you should use SDL_LockHashTable() if necessary 59 + // This function is not thread-safe, you should use external locking if you use this function 63 60 extern bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter); 64 61 65 62 // iterate all key/value pairs in a hash (stackable hashes can have duplicate keys with multiple values). 66 - // This function is not thread-safe, you should use SDL_LockHashTable() if necessary 63 + // This function is not thread-safe, you should use external locking if you use this function 67 64 extern bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter); 68 65 69 66 extern Uint32 SDL_HashPointer(const void *key, void *unused);
+37 -19
src/camera/SDL_camera.c
··· 299 299 { 300 300 if (SDL_AtomicDecRef(&device->refcount)) { 301 301 // take it out of the device list. 302 + SDL_LockRWLockForWriting(camera_driver.device_hash_lock); 302 303 if (SDL_RemoveFromHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id)) { 303 304 SDL_AddAtomicInt(&camera_driver.device_count, -1); 304 305 } 306 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 305 307 DestroyPhysicalCamera(device); // ...and nuke it. 306 308 } 307 309 } ··· 327 329 } 328 330 329 331 SDL_Camera *device = NULL; 332 + SDL_LockRWLockForReading(camera_driver.device_hash_lock); 330 333 SDL_FindInHashTable(camera_driver.device_hash, (const void *) (uintptr_t) devid, (const void **) &device); 334 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 331 335 if (!device) { 332 336 SDL_SetError("Invalid camera device instance ID"); 333 337 } else { ··· 420 424 SDL_assert((specs != NULL) == (num_specs > 0)); 421 425 SDL_assert(handle != NULL); 422 426 427 + SDL_LockRWLockForReading(camera_driver.device_hash_lock); 423 428 const int shutting_down = SDL_GetAtomicInt(&camera_driver.shutting_down); 429 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 424 430 if (shutting_down) { 425 431 return NULL; // we're shutting down, don't add any devices that are hotplugged at the last possible moment. 426 432 } ··· 490 496 SDL_SetAtomicInt(&device->zombie, 0); 491 497 RefPhysicalCamera(device); 492 498 499 + SDL_LockRWLockForWriting(camera_driver.device_hash_lock); 493 500 if (SDL_InsertIntoHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id, device)) { 494 501 SDL_AddAtomicInt(&camera_driver.device_count, 1); 495 502 } else { ··· 507 514 p->type = SDL_EVENT_CAMERA_DEVICE_ADDED; 508 515 p->devid = device->instance_id; 509 516 p->next = NULL; 510 - SDL_LockHashTable(camera_driver.device_hash, true); 511 517 SDL_assert(camera_driver.pending_events_tail != NULL); 512 518 SDL_assert(camera_driver.pending_events_tail->next == NULL); 513 519 camera_driver.pending_events_tail->next = p; 514 520 camera_driver.pending_events_tail = p; 515 - SDL_UnlockHashTable(camera_driver.device_hash); 516 521 } 517 522 } 523 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 518 524 519 525 return device; 520 526 } ··· 568 574 569 575 if (first_disconnect) { 570 576 if (pending.next) { // NULL if event is disabled or disaster struck. 571 - SDL_LockHashTable(camera_driver.device_hash, true); 577 + SDL_LockRWLockForWriting(camera_driver.device_hash_lock); 572 578 SDL_assert(camera_driver.pending_events_tail != NULL); 573 579 SDL_assert(camera_driver.pending_events_tail->next == NULL); 574 580 camera_driver.pending_events_tail->next = pending.next; 575 581 camera_driver.pending_events_tail = pending_tail; 576 - SDL_UnlockHashTable(camera_driver.device_hash); 582 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 577 583 } 578 584 } 579 585 } ··· 606 612 ReleaseCamera(device); 607 613 608 614 if (pending.next) { // NULL if event is disabled or disaster struck. 609 - SDL_LockHashTable(camera_driver.device_hash, true); 615 + SDL_LockRWLockForWriting(camera_driver.device_hash_lock); 610 616 SDL_assert(camera_driver.pending_events_tail != NULL); 611 617 SDL_assert(camera_driver.pending_events_tail->next == NULL); 612 618 camera_driver.pending_events_tail->next = pending.next; 613 619 camera_driver.pending_events_tail = pending_tail; 614 - SDL_UnlockHashTable(camera_driver.device_hash); 620 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 615 621 } 616 622 } 617 623 ··· 627 633 const void *value; 628 634 void *iter = NULL; 629 635 630 - SDL_LockHashTable(camera_driver.device_hash, false); 636 + SDL_LockRWLockForReading(camera_driver.device_hash_lock); 631 637 while (SDL_IterateHashTable(camera_driver.device_hash, &key, &value, &iter)) { 632 638 SDL_Camera *device = (SDL_Camera *) value; 633 639 if (callback(device, userdata)) { // found it? 634 - SDL_UnlockHashTable(camera_driver.device_hash); 640 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 635 641 return device; 636 642 } 637 643 } 638 - SDL_UnlockHashTable(camera_driver.device_hash); 644 + 645 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 639 646 640 647 SDL_SetError("Device not found"); 641 648 return NULL; ··· 709 716 710 717 SDL_CameraID *result = NULL; 711 718 712 - SDL_LockHashTable(camera_driver.device_hash, false); 719 + SDL_LockRWLockForReading(camera_driver.device_hash_lock); 713 720 int num_devices = SDL_GetAtomicInt(&camera_driver.device_count); 714 721 result = (SDL_CameraID *) SDL_malloc((num_devices + 1) * sizeof (SDL_CameraID)); 715 722 if (!result) { ··· 726 733 SDL_assert(devs_seen == num_devices); 727 734 result[devs_seen] = 0; // null-terminated. 728 735 } 729 - SDL_UnlockHashTable(camera_driver.device_hash); 736 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 730 737 731 738 *count = num_devices; 732 739 ··· 1356 1363 return; 1357 1364 } 1358 1365 1359 - SDL_HashTable *device_hash = camera_driver.device_hash; 1360 - SDL_LockHashTable(device_hash, true); 1366 + SDL_LockRWLockForWriting(camera_driver.device_hash_lock); 1361 1367 SDL_SetAtomicInt(&camera_driver.shutting_down, 1); 1368 + SDL_HashTable *device_hash = camera_driver.device_hash; 1362 1369 camera_driver.device_hash = NULL; 1363 1370 SDL_PendingCameraEvent *pending_events = camera_driver.pending_events.next; 1364 1371 camera_driver.pending_events.next = NULL; 1365 1372 SDL_SetAtomicInt(&camera_driver.device_count, 0); 1366 - SDL_UnlockHashTable(device_hash); 1373 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 1367 1374 1368 1375 SDL_PendingCameraEvent *pending_next = NULL; 1369 1376 for (SDL_PendingCameraEvent *i = pending_events; i; i = pending_next) { ··· 1381 1388 // Free the driver data 1382 1389 camera_driver.impl.Deinitialize(); 1383 1390 1391 + SDL_DestroyRWLock(camera_driver.device_hash_lock); 1384 1392 SDL_DestroyHashTable(device_hash); 1385 1393 1386 1394 SDL_zero(camera_driver); ··· 1409 1417 SDL_QuitCamera(); // shutdown driver if already running. 1410 1418 } 1411 1419 1412 - SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashCameraID, MatchCameraID, NukeCameraHashItem, true, false); 1420 + SDL_RWLock *device_hash_lock = SDL_CreateRWLock(); // create this early, so if it fails we don't have to tear down the whole camera subsystem. 1421 + if (!device_hash_lock) { 1422 + return false; 1423 + } 1424 + 1425 + SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashCameraID, MatchCameraID, NukeCameraHashItem, false, false); 1413 1426 if (!device_hash) { 1427 + SDL_DestroyRWLock(device_hash_lock); 1414 1428 return false; 1415 1429 } 1416 1430 ··· 1427 1441 const char *driver_attempt = driver_name_copy; 1428 1442 1429 1443 if (!driver_name_copy) { 1444 + SDL_DestroyRWLock(device_hash_lock); 1430 1445 SDL_DestroyHashTable(device_hash); 1431 1446 return false; 1432 1447 } ··· 1442 1457 tried_to_init = true; 1443 1458 SDL_zero(camera_driver); 1444 1459 camera_driver.pending_events_tail = &camera_driver.pending_events; 1460 + camera_driver.device_hash_lock = device_hash_lock; 1445 1461 camera_driver.device_hash = device_hash; 1446 1462 if (bootstrap[i]->init(&camera_driver.impl)) { 1447 1463 camera_driver.name = bootstrap[i]->name; ··· 1465 1481 tried_to_init = true; 1466 1482 SDL_zero(camera_driver); 1467 1483 camera_driver.pending_events_tail = &camera_driver.pending_events; 1484 + camera_driver.device_hash_lock = device_hash_lock; 1468 1485 camera_driver.device_hash = device_hash; 1469 1486 if (bootstrap[i]->init(&camera_driver.impl)) { 1470 1487 camera_driver.name = bootstrap[i]->name; ··· 1485 1502 } 1486 1503 1487 1504 SDL_zero(camera_driver); 1505 + SDL_DestroyRWLock(device_hash_lock); 1488 1506 SDL_DestroyHashTable(device_hash); 1489 1507 return false; // No driver was available, so fail. 1490 1508 } ··· 1501 1519 // ("UpdateSubsystem" is the same naming that the other things that hook into PumpEvents use.) 1502 1520 void SDL_UpdateCamera(void) 1503 1521 { 1504 - SDL_LockHashTable(camera_driver.device_hash, false); 1522 + SDL_LockRWLockForReading(camera_driver.device_hash_lock); 1505 1523 SDL_PendingCameraEvent *pending_events = camera_driver.pending_events.next; 1506 - SDL_UnlockHashTable(camera_driver.device_hash); 1524 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 1507 1525 1508 1526 if (!pending_events) { 1509 1527 return; // nothing to do, check next time. 1510 1528 } 1511 1529 1512 1530 // okay, let's take this whole list of events so we can dump the lock, and new ones can queue up for a later update. 1513 - SDL_LockHashTable(camera_driver.device_hash, true); 1531 + SDL_LockRWLockForWriting(camera_driver.device_hash_lock); 1514 1532 pending_events = camera_driver.pending_events.next; // in case this changed... 1515 1533 camera_driver.pending_events.next = NULL; 1516 1534 camera_driver.pending_events_tail = &camera_driver.pending_events; 1517 - SDL_UnlockHashTable(camera_driver.device_hash); 1535 + SDL_UnlockRWLock(camera_driver.device_hash_lock); 1518 1536 1519 1537 SDL_PendingCameraEvent *pending_next = NULL; 1520 1538 for (SDL_PendingCameraEvent *i = pending_events; i; i = pending_next) {
+32 -10
src/stdlib/SDL_getenv.c
··· 53 53 54 54 struct SDL_Environment 55 55 { 56 + SDL_Mutex *lock; 56 57 SDL_HashTable *strings; 57 58 }; 58 59 static SDL_Environment *SDL_environment; ··· 87 88 return NULL; 88 89 } 89 90 90 - env->strings = SDL_CreateHashTable(NULL, 16, SDL_HashString, SDL_KeyMatchString, SDL_NukeFreeKey, true, false); 91 + env->strings = SDL_CreateHashTable(NULL, 16, SDL_HashString, SDL_KeyMatchString, SDL_NukeFreeKey, false, false); 91 92 if (!env->strings) { 92 93 SDL_free(env); 93 94 return NULL; 94 95 } 96 + 97 + // Don't fail if we can't create a mutex (e.g. on a single-thread environment) 98 + env->lock = SDL_CreateMutex(); 95 99 96 100 if (populated) { 97 101 #ifdef SDL_PLATFORM_WINDOWS ··· 153 157 return NULL; 154 158 } 155 159 156 - const char *value; 157 - if (SDL_FindInHashTable(env->strings, name, (const void **)&value)) { 158 - result = SDL_GetPersistentString(value); 160 + SDL_LockMutex(env->lock); 161 + { 162 + const char *value; 163 + 164 + if (SDL_FindInHashTable(env->strings, name, (const void **)&value)) { 165 + result = SDL_GetPersistentString(value); 166 + } 159 167 } 168 + SDL_UnlockMutex(env->lock); 160 169 161 170 return result; 162 171 } ··· 170 179 return NULL; 171 180 } 172 181 173 - SDL_LockHashTable(env->strings, false); 182 + SDL_LockMutex(env->lock); 174 183 { 175 184 size_t count, length = 0; 176 185 void *iter; ··· 207 216 } 208 217 result[count] = NULL; 209 218 } 210 - SDL_UnlockHashTable(env->strings); 219 + SDL_UnlockMutex(env->lock); 211 220 212 221 return result; 213 222 } ··· 224 233 return SDL_InvalidParamError("value"); 225 234 } 226 235 227 - SDL_LockHashTable(env->strings, true); 236 + SDL_LockMutex(env->lock); 228 237 { 229 238 const void *existing_value; 230 239 bool insert = true; ··· 249 258 } 250 259 } 251 260 } 252 - SDL_UnlockHashTable(env->strings); 261 + SDL_UnlockMutex(env->lock); 253 262 254 263 return result; 255 264 } 256 265 257 266 bool SDL_UnsetEnvironmentVariable(SDL_Environment *env, const char *name) 258 267 { 268 + bool result = false; 269 + 259 270 if (!env) { 260 271 return SDL_InvalidParamError("env"); 261 272 } else if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) { 262 273 return SDL_InvalidParamError("name"); 263 274 } 264 275 265 - SDL_RemoveFromHashTable(env->strings, name); 266 - return true; 276 + SDL_LockMutex(env->lock); 277 + { 278 + const void *value; 279 + if (SDL_FindInHashTable(env->strings, name, &value)) { 280 + result = SDL_RemoveFromHashTable(env->strings, name); 281 + } else { 282 + result = true; 283 + } 284 + } 285 + SDL_UnlockMutex(env->lock); 286 + 287 + return result; 267 288 } 268 289 269 290 void SDL_DestroyEnvironment(SDL_Environment *env) ··· 272 293 return; 273 294 } 274 295 296 + SDL_DestroyMutex(env->lock); 275 297 SDL_DestroyHashTable(env->strings); 276 298 SDL_free(env); 277 299 }