forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[threading] Switch to a native implementation of LowLevelLifoSemaphore (
dotnet#2098) This change is motivated on two main fronts. The first is maintainability - the current managed implementation is difficult to understand and I worry diagnosing any potential issues would be a massive time sink. The second is performance - the current implementation appears to suffer from significant lock contention when running the TechEmpower plaintext benchmark. My hope is that the simpler, cleaner native implementation here will avoid both problems, but I don't want to merge it until we have benchmarking data. However, even if the numbers are similar, I still think it's worth merging just from a maintainability perspective. The native LifoSemaphore implementation has only ever been tested on posix-like platforms, so Windows behavior is unknown. Currently the Windows implementation of LowLevelLifoSemaphore is very different, so unless we have need for the LifoSemaphore elsewhere in the runtime this isn't a concern. Many thanks to @filipnavara for the initial implementation.
- Loading branch information
1 parent
084dd1a
commit 3eaff60
Showing
9 changed files
with
192 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
#include <mono/utils/lifo-semaphore.h> | ||
|
||
LifoSemaphore * | ||
mono_lifo_semaphore_init (void) | ||
{ | ||
LifoSemaphore *semaphore = g_new0 (LifoSemaphore, 1); | ||
if (semaphore == NULL) | ||
return NULL; | ||
|
||
mono_coop_mutex_init (&semaphore->mutex); | ||
|
||
return semaphore; | ||
} | ||
|
||
void | ||
mono_lifo_semaphore_delete (LifoSemaphore *semaphore) | ||
{ | ||
g_assert (semaphore->head == NULL); | ||
mono_coop_mutex_destroy (&semaphore->mutex); | ||
g_free (semaphore); | ||
} | ||
|
||
int32_t | ||
mono_lifo_semaphore_timed_wait (LifoSemaphore *semaphore, int32_t timeout_ms) | ||
{ | ||
LifoSemaphoreWaitEntry wait_entry = { 0 }; | ||
|
||
mono_coop_cond_init (&wait_entry.condition); | ||
mono_coop_mutex_lock (&semaphore->mutex); | ||
|
||
if (semaphore->pending_signals > 0) { | ||
--semaphore->pending_signals; | ||
mono_coop_cond_destroy (&wait_entry.condition); | ||
mono_coop_mutex_unlock (&semaphore->mutex); | ||
return 1; | ||
} | ||
|
||
// Enqueue out entry into the LIFO wait list | ||
wait_entry.previous = NULL; | ||
wait_entry.next = semaphore->head; | ||
if (semaphore->head != NULL) | ||
semaphore->head->previous = &wait_entry; | ||
semaphore->head = &wait_entry; | ||
|
||
// Wait for a signal or timeout | ||
int wait_error = 0; | ||
do { | ||
wait_error = mono_coop_cond_timedwait (&wait_entry.condition, &semaphore->mutex, timeout_ms); | ||
} while (wait_error == 0 && !wait_entry.signaled); | ||
|
||
if (wait_error == -1) { | ||
if (semaphore->head == &wait_entry) | ||
semaphore->head = wait_entry.next; | ||
if (wait_entry.next != NULL) | ||
wait_entry.next->previous = wait_entry.previous; | ||
if (wait_entry.previous != NULL) | ||
wait_entry.previous->next = wait_entry.next; | ||
} | ||
|
||
mono_coop_cond_destroy (&wait_entry.condition); | ||
mono_coop_mutex_unlock (&semaphore->mutex); | ||
|
||
return wait_entry.signaled; | ||
} | ||
|
||
void | ||
mono_lifo_semaphore_release (LifoSemaphore *semaphore, uint32_t count) | ||
{ | ||
mono_coop_mutex_lock (&semaphore->mutex); | ||
|
||
while (count > 0) { | ||
LifoSemaphoreWaitEntry *wait_entry = semaphore->head; | ||
if (wait_entry != NULL) { | ||
semaphore->head = wait_entry->next; | ||
if (semaphore->head != NULL) | ||
semaphore->head->previous = NULL; | ||
wait_entry->previous = NULL; | ||
wait_entry->next = NULL; | ||
wait_entry->signaled = 1; | ||
mono_coop_cond_signal (&wait_entry->condition); | ||
--count; | ||
} else { | ||
semaphore->pending_signals += count; | ||
count = 0; | ||
} | ||
} | ||
|
||
mono_coop_mutex_unlock (&semaphore->mutex); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#ifndef __MONO_LIFO_SEMAPHORE_H__ | ||
#define __MONO_LIFO_SEMAPHORE_H__ | ||
|
||
#include <mono/utils/mono-coop-mutex.h> | ||
|
||
typedef struct _LifoSemaphore LifoSemaphore; | ||
typedef struct _LifoSemaphoreWaitEntry LifoSemaphoreWaitEntry; | ||
|
||
struct _LifoSemaphoreWaitEntry { | ||
MonoCoopCond condition; | ||
int signaled; | ||
LifoSemaphoreWaitEntry *previous; | ||
LifoSemaphoreWaitEntry *next; | ||
}; | ||
|
||
struct _LifoSemaphore { | ||
MonoCoopMutex mutex; | ||
LifoSemaphoreWaitEntry *head; | ||
uint32_t pending_signals; | ||
}; | ||
|
||
LifoSemaphore * | ||
mono_lifo_semaphore_init (void); | ||
|
||
void | ||
mono_lifo_semaphore_delete (LifoSemaphore *semaphore); | ||
|
||
int32_t | ||
mono_lifo_semaphore_timed_wait (LifoSemaphore *semaphore, int32_t timeout_ms); | ||
|
||
void | ||
mono_lifo_semaphore_release (LifoSemaphore *semaphore, uint32_t count); | ||
|
||
#endif // __MONO_LIFO_SEMAPHORE_H__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters