Fix a race condition when setting the callbacks

When acquiring the reader's lock (sem_sync()...sem_release()), it is
possible for a writer to squeeze by if the reader goes into sync_wait().
The writer could re-acquire the entry.sync between entry.sem > 0 and
entry.sync = 0.

void sync_wait(uint32_t id) {
    sem_decrement(id);
    while (entry(id).sync.load()) {}
    // <--- HERE
    sem_increment(id);
}

This could result in both the reader and the writer accessing
{ callback, arg } at the same time, and the reader could read
inconsistent data, for example: { new callback, old arg }.

The solution is to re-test entry.sync when returning from sync_wait():

void sem_sync(uint32_t id) {
    sem_increment(id);
-   if (entry(id).sync.load() == true) sync_wait(id);
+   while (entry(id).sync.load() == true) sync_wait(id);
}

Change-Id: I22f74f4cb9a5f027aac8aa4ed3e633acc19df4b8
Tento commit je obsažen v:
Laurent Morichetti
2022-07-29 17:13:25 -07:00
odevzdal Laurent Morichetti
rodič e1f1e38d79
revize 6f78083f2a
+1 -1
Zobrazit soubor
@@ -134,7 +134,7 @@ class api_callbacks_table_t {
inline void sem_sync(const uint32_t& id) {
sem_increment(id);
if (entry(id).sync.load() == true) sync_wait(id);
while (entry(id).sync.load() == true) sync_wait(id);
}
inline void sem_release(const uint32_t& id) {