diff options
author | Marek Olšák <[email protected]> | 2017-02-20 15:27:07 +0100 |
---|---|---|
committer | Marek Olšák <[email protected]> | 2017-02-22 20:26:39 +0100 |
commit | 4aea8fe7e01f2b65ffad3982687f90c8fa941524 (patch) | |
tree | 2296d59c8c600f9d261b6f03095c0f6ffa7834d6 /src/gallium/auxiliary/util | |
parent | a96c9564e319cb387a9acf4981383cc77b018d0f (diff) |
gallium/u_queue: fix random crashes when the app calls exit()
This fixes:
vdpauinfo: ../lib/CodeGen/TargetPassConfig.cpp:579: virtual void
llvm::TargetPassConfig::addMachinePasses(): Assertion `TPI && IPI &&
"Pass ID not registered!"' failed.
v2: use list_head, switch the call order in destroy
Cc: 13.0 17.0 <[email protected]>
Reviewed-by: Nicolai Hähnle <[email protected]>
Diffstat (limited to 'src/gallium/auxiliary/util')
-rw-r--r-- | src/gallium/auxiliary/util/u_queue.c | 76 | ||||
-rw-r--r-- | src/gallium/auxiliary/util/u_queue.h | 4 |
2 files changed, 78 insertions, 2 deletions
diff --git a/src/gallium/auxiliary/util/u_queue.c b/src/gallium/auxiliary/util/u_queue.c index 4da5d8e9f8c..52cfc0a4bf2 100644 --- a/src/gallium/auxiliary/util/u_queue.c +++ b/src/gallium/auxiliary/util/u_queue.c @@ -29,6 +29,68 @@ #include "u_string.h" #include "os/os_time.h" +static void util_queue_killall_and_wait(struct util_queue *queue); + +/**************************************************************************** + * Wait for all queues to assert idle when exit() is called. + * + * Otherwise, C++ static variable destructors can be called while threads + * are using the static variables. + */ + +static once_flag atexit_once_flag = ONCE_FLAG_INIT; +static struct list_head queue_list; +pipe_static_mutex(exit_mutex); + +static void +atexit_handler(void) +{ + struct util_queue *iter; + + pipe_mutex_lock(exit_mutex); + /* Wait for all queues to assert idle. */ + LIST_FOR_EACH_ENTRY(iter, &queue_list, head) { + util_queue_killall_and_wait(iter); + } + pipe_mutex_unlock(exit_mutex); +} + +static void +global_init(void) +{ + LIST_INITHEAD(&queue_list); + atexit(atexit_handler); +} + +static void +add_to_atexit_list(struct util_queue *queue) +{ + call_once(&atexit_once_flag, global_init); + + pipe_mutex_lock(exit_mutex); + LIST_ADD(&queue->head, &queue_list); + pipe_mutex_unlock(exit_mutex); +} + +static void +remove_from_atexit_list(struct util_queue *queue) +{ + struct util_queue *iter, *tmp; + + pipe_mutex_lock(exit_mutex); + LIST_FOR_EACH_ENTRY_SAFE(iter, tmp, &queue_list, head) { + if (iter == queue) { + LIST_DEL(&iter->head); + break; + } + } + pipe_mutex_unlock(exit_mutex); +} + +/**************************************************************************** + * util_queue implementation + */ + static void util_queue_fence_signal(struct util_queue_fence *fence) { @@ -104,6 +166,7 @@ static PIPE_THREAD_ROUTINE(util_queue_thread_func, input) queue->jobs[queue->read_idx].job = NULL; queue->read_idx = (queue->read_idx + 1) % queue->max_jobs; } + queue->num_queued = 0; /* reset this when exiting the thread */ pipe_mutex_unlock(queue->lock); return 0; } @@ -157,6 +220,8 @@ util_queue_init(struct util_queue *queue, } } } + + add_to_atexit_list(queue); return true; fail: @@ -173,8 +238,8 @@ fail: return false; } -void -util_queue_destroy(struct util_queue *queue) +static void +util_queue_killall_and_wait(struct util_queue *queue) { unsigned i; @@ -186,6 +251,13 @@ util_queue_destroy(struct util_queue *queue) for (i = 0; i < queue->num_threads; i++) pipe_thread_wait(queue->threads[i]); +} + +void +util_queue_destroy(struct util_queue *queue) +{ + util_queue_killall_and_wait(queue); + remove_from_atexit_list(queue); pipe_condvar_destroy(queue->has_space_cond); pipe_condvar_destroy(queue->has_queued_cond); diff --git a/src/gallium/auxiliary/util/u_queue.h b/src/gallium/auxiliary/util/u_queue.h index 351315c5780..335813f63c1 100644 --- a/src/gallium/auxiliary/util/u_queue.h +++ b/src/gallium/auxiliary/util/u_queue.h @@ -34,6 +34,7 @@ #define U_QUEUE_H #include "os/os_thread.h" +#include "util/list.h" /* Job completion fence. * Put this into your job structure. @@ -66,6 +67,9 @@ struct util_queue { int max_jobs; int write_idx, read_idx; /* ring buffer pointers */ struct util_queue_job *jobs; + + /* for cleanup at exit(), protected by exit_mutex */ + struct list_head head; }; bool util_queue_init(struct util_queue *queue, |