mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-22 15:40:11 +01:00
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 <mesa-stable@lists.freedesktop.org>
Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
This commit is contained in:
parent
a96c9564e3
commit
4aea8fe7e0
2 changed files with 78 additions and 2 deletions
|
|
@ -29,6 +29,68 @@
|
||||||
#include "u_string.h"
|
#include "u_string.h"
|
||||||
#include "os/os_time.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
|
static void
|
||||||
util_queue_fence_signal(struct util_queue_fence *fence)
|
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->jobs[queue->read_idx].job = NULL;
|
||||||
queue->read_idx = (queue->read_idx + 1) % queue->max_jobs;
|
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);
|
pipe_mutex_unlock(queue->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -157,6 +220,8 @@ util_queue_init(struct util_queue *queue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add_to_atexit_list(queue);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|
@ -173,8 +238,8 @@ fail:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
util_queue_destroy(struct util_queue *queue)
|
util_queue_killall_and_wait(struct util_queue *queue)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
|
|
@ -186,6 +251,13 @@ util_queue_destroy(struct util_queue *queue)
|
||||||
|
|
||||||
for (i = 0; i < queue->num_threads; i++)
|
for (i = 0; i < queue->num_threads; i++)
|
||||||
pipe_thread_wait(queue->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_space_cond);
|
||||||
pipe_condvar_destroy(queue->has_queued_cond);
|
pipe_condvar_destroy(queue->has_queued_cond);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
#define U_QUEUE_H
|
#define U_QUEUE_H
|
||||||
|
|
||||||
#include "os/os_thread.h"
|
#include "os/os_thread.h"
|
||||||
|
#include "util/list.h"
|
||||||
|
|
||||||
/* Job completion fence.
|
/* Job completion fence.
|
||||||
* Put this into your job structure.
|
* Put this into your job structure.
|
||||||
|
|
@ -66,6 +67,9 @@ struct util_queue {
|
||||||
int max_jobs;
|
int max_jobs;
|
||||||
int write_idx, read_idx; /* ring buffer pointers */
|
int write_idx, read_idx; /* ring buffer pointers */
|
||||||
struct util_queue_job *jobs;
|
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,
|
bool util_queue_init(struct util_queue *queue,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue