mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 23:46:17 +01:00
GThreadPool: Always use the thread-spawning thread for the global shared thread pool
Setting the main thread's scheduler settings is not reliably possible, especially not if SELinux or similar mechanisms are used to limit what can be done. As such, get rid of all the complicated code that tried to do this better and use a separate thread for spawning threads for the global shared thread pool. These will always inherit the priority of the main thread (or rather the thread that created the first shared thread pool). Fixes https://gitlab.gnome.org/GNOME/glib/-/issues/2769
This commit is contained in:
parent
438006899e
commit
4d2e77a554
@ -376,7 +376,7 @@ g_thread_create_full (GThreadFunc func,
|
|||||||
GThread *thread;
|
GThread *thread;
|
||||||
|
|
||||||
thread = g_thread_new_internal (NULL, g_deprecated_thread_proxy,
|
thread = g_thread_new_internal (NULL, g_deprecated_thread_proxy,
|
||||||
func, data, stack_size, NULL, error);
|
func, data, stack_size, error);
|
||||||
|
|
||||||
if (thread && !joinable)
|
if (thread && !joinable)
|
||||||
{
|
{
|
||||||
|
@ -1157,9 +1157,6 @@ typedef struct
|
|||||||
GMutex lock;
|
GMutex lock;
|
||||||
|
|
||||||
void *(*proxy) (void *);
|
void *(*proxy) (void *);
|
||||||
|
|
||||||
/* Must be statically allocated and valid forever */
|
|
||||||
const GThreadSchedulerSettings *scheduler_settings;
|
|
||||||
} GThreadPosix;
|
} GThreadPosix;
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1175,103 +1172,9 @@ g_system_thread_free (GRealThread *thread)
|
|||||||
g_slice_free (GThreadPosix, pt);
|
g_slice_free (GThreadPosix, pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
|
||||||
g_system_thread_get_scheduler_settings (GThreadSchedulerSettings *scheduler_settings)
|
|
||||||
{
|
|
||||||
/* FIXME: Implement the same for macOS and the BSDs so it doesn't go through
|
|
||||||
* the fallback code using an additional thread. */
|
|
||||||
#if defined(HAVE_SYS_SCHED_GETATTR)
|
|
||||||
pid_t tid;
|
|
||||||
int res;
|
|
||||||
/* FIXME: The struct definition does not seem to be possible to pull in
|
|
||||||
* via any of the normal system headers and it's only declared in the
|
|
||||||
* kernel headers. That's why we hardcode 56 here right now. */
|
|
||||||
guint size = 56; /* Size as of Linux 5.3.9 */
|
|
||||||
guint flags = 0;
|
|
||||||
|
|
||||||
tid = (pid_t) syscall (SYS_gettid);
|
|
||||||
|
|
||||||
scheduler_settings->attr = g_malloc0 (size);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
int errsv;
|
|
||||||
|
|
||||||
res = syscall (SYS_sched_getattr, tid, scheduler_settings->attr, size, flags);
|
|
||||||
errsv = errno;
|
|
||||||
if (res == -1)
|
|
||||||
{
|
|
||||||
if (errsv == EAGAIN)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (errsv == E2BIG)
|
|
||||||
{
|
|
||||||
g_assert (size < G_MAXINT);
|
|
||||||
size *= 2;
|
|
||||||
scheduler_settings->attr = g_realloc (scheduler_settings->attr, size);
|
|
||||||
/* Needs to be zero-initialized */
|
|
||||||
memset (scheduler_settings->attr, 0, size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_debug ("Failed to get thread scheduler attributes: %s", g_strerror (errsv));
|
|
||||||
g_free (scheduler_settings->attr);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (res == -1);
|
|
||||||
|
|
||||||
/* Try setting them on the current thread to see if any system policies are
|
|
||||||
* in place that would disallow doing so */
|
|
||||||
res = syscall (SYS_sched_setattr, tid, scheduler_settings->attr, flags);
|
|
||||||
if (res == -1)
|
|
||||||
{
|
|
||||||
int errsv = errno;
|
|
||||||
|
|
||||||
g_debug ("Failed to set thread scheduler attributes: %s", g_strerror (errsv));
|
|
||||||
g_free (scheduler_settings->attr);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
#else
|
|
||||||
return FALSE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(HAVE_SYS_SCHED_GETATTR)
|
|
||||||
static void *
|
|
||||||
linux_pthread_proxy (void *data)
|
|
||||||
{
|
|
||||||
GThreadPosix *thread = data;
|
|
||||||
|
|
||||||
/* Set scheduler settings first if requested */
|
|
||||||
if (thread->scheduler_settings)
|
|
||||||
{
|
|
||||||
pid_t tid = 0;
|
|
||||||
guint flags = 0;
|
|
||||||
int res;
|
|
||||||
int errsv;
|
|
||||||
|
|
||||||
tid = (pid_t) syscall (SYS_gettid);
|
|
||||||
res = syscall (SYS_sched_setattr, tid, thread->scheduler_settings->attr, flags);
|
|
||||||
errsv = errno;
|
|
||||||
if (res == -1)
|
|
||||||
g_error ("Failed to set scheduler settings: %s", g_strerror (errsv));
|
|
||||||
}
|
|
||||||
|
|
||||||
return thread->proxy (data);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GRealThread *
|
GRealThread *
|
||||||
g_system_thread_new (GThreadFunc proxy,
|
g_system_thread_new (GThreadFunc proxy,
|
||||||
gulong stack_size,
|
gulong stack_size,
|
||||||
const GThreadSchedulerSettings *scheduler_settings,
|
|
||||||
const char *name,
|
const char *name,
|
||||||
GThreadFunc func,
|
GThreadFunc func,
|
||||||
gpointer data,
|
gpointer data,
|
||||||
@ -1290,7 +1193,6 @@ g_system_thread_new (GThreadFunc proxy,
|
|||||||
base_thread->thread.func = func;
|
base_thread->thread.func = func;
|
||||||
base_thread->thread.data = data;
|
base_thread->thread.data = data;
|
||||||
base_thread->name = g_strdup (name);
|
base_thread->name = g_strdup (name);
|
||||||
thread->scheduler_settings = scheduler_settings;
|
|
||||||
thread->proxy = proxy;
|
thread->proxy = proxy;
|
||||||
|
|
||||||
posix_check_cmd (pthread_attr_init (&attr));
|
posix_check_cmd (pthread_attr_init (&attr));
|
||||||
@ -1310,18 +1212,13 @@ g_system_thread_new (GThreadFunc proxy,
|
|||||||
#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
|
#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
|
||||||
|
|
||||||
#ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED
|
#ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED
|
||||||
if (!scheduler_settings)
|
|
||||||
{
|
{
|
||||||
/* While this is the default, better be explicit about it */
|
/* While this is the default, better be explicit about it */
|
||||||
pthread_attr_setinheritsched (&attr, PTHREAD_INHERIT_SCHED);
|
pthread_attr_setinheritsched (&attr, PTHREAD_INHERIT_SCHED);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_PTHREAD_ATTR_SETINHERITSCHED */
|
#endif /* HAVE_PTHREAD_ATTR_SETINHERITSCHED */
|
||||||
|
|
||||||
#if defined(HAVE_SYS_SCHED_GETATTR)
|
|
||||||
ret = pthread_create (&thread->system_thread, &attr, linux_pthread_proxy, thread);
|
|
||||||
#else
|
|
||||||
ret = pthread_create (&thread->system_thread, &attr, (void* (*)(void*))proxy, thread);
|
ret = pthread_create (&thread->system_thread, &attr, (void* (*)(void*))proxy, thread);
|
||||||
#endif
|
|
||||||
|
|
||||||
posix_check_cmd (pthread_attr_destroy (&attr));
|
posix_check_cmd (pthread_attr_destroy (&attr));
|
||||||
|
|
||||||
|
@ -463,19 +463,9 @@ g_thread_win32_proxy (gpointer data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
|
||||||
g_system_thread_get_scheduler_settings (GThreadSchedulerSettings *scheduler_settings)
|
|
||||||
{
|
|
||||||
HANDLE current_thread = GetCurrentThread ();
|
|
||||||
scheduler_settings->thread_prio = GetThreadPriority (current_thread);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
GRealThread *
|
GRealThread *
|
||||||
g_system_thread_new (GThreadFunc proxy,
|
g_system_thread_new (GThreadFunc proxy,
|
||||||
gulong stack_size,
|
gulong stack_size,
|
||||||
const GThreadSchedulerSettings *scheduler_settings,
|
|
||||||
const char *name,
|
const char *name,
|
||||||
GThreadFunc func,
|
GThreadFunc func,
|
||||||
gpointer data,
|
gpointer data,
|
||||||
@ -515,16 +505,10 @@ g_system_thread_new (GThreadFunc proxy,
|
|||||||
* On Windows, by default all new threads are created with NORMAL thread
|
* On Windows, by default all new threads are created with NORMAL thread
|
||||||
* priority.
|
* priority.
|
||||||
*/
|
*/
|
||||||
|
{
|
||||||
if (scheduler_settings)
|
HANDLE current_thread = GetCurrentThread ();
|
||||||
{
|
thread_prio = GetThreadPriority (current_thread);
|
||||||
thread_prio = scheduler_settings->thread_prio;
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HANDLE current_thread = GetCurrentThread ();
|
|
||||||
thread_prio = GetThreadPriority (current_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread_prio == THREAD_PRIORITY_ERROR_RETURN)
|
if (thread_prio == THREAD_PRIORITY_ERROR_RETURN)
|
||||||
{
|
{
|
||||||
|
@ -885,7 +885,7 @@ g_thread_new (const gchar *name,
|
|||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GThread *thread;
|
GThread *thread;
|
||||||
|
|
||||||
thread = g_thread_new_internal (name, g_thread_proxy, func, data, 0, NULL, &error);
|
thread = g_thread_new_internal (name, g_thread_proxy, func, data, 0, &error);
|
||||||
|
|
||||||
if G_UNLIKELY (thread == NULL)
|
if G_UNLIKELY (thread == NULL)
|
||||||
g_error ("creating thread '%s': %s", name ? name : "", error->message);
|
g_error ("creating thread '%s': %s", name ? name : "", error->message);
|
||||||
@ -916,7 +916,7 @@ g_thread_try_new (const gchar *name,
|
|||||||
gpointer data,
|
gpointer data,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
return g_thread_new_internal (name, g_thread_proxy, func, data, 0, NULL, error);
|
return g_thread_new_internal (name, g_thread_proxy, func, data, 0, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
GThread *
|
GThread *
|
||||||
@ -925,7 +925,6 @@ g_thread_new_internal (const gchar *name,
|
|||||||
GThreadFunc func,
|
GThreadFunc func,
|
||||||
gpointer data,
|
gpointer data,
|
||||||
gsize stack_size,
|
gsize stack_size,
|
||||||
const GThreadSchedulerSettings *scheduler_settings,
|
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (func != NULL, NULL);
|
g_return_val_if_fail (func != NULL, NULL);
|
||||||
@ -933,16 +932,7 @@ g_thread_new_internal (const gchar *name,
|
|||||||
g_atomic_int_inc (&g_thread_n_created_counter);
|
g_atomic_int_inc (&g_thread_n_created_counter);
|
||||||
|
|
||||||
g_trace_mark (G_TRACE_CURRENT_TIME, 0, "GLib", "GThread created", "%s", name ? name : "(unnamed)");
|
g_trace_mark (G_TRACE_CURRENT_TIME, 0, "GLib", "GThread created", "%s", name ? name : "(unnamed)");
|
||||||
return (GThread *) g_system_thread_new (proxy, stack_size, scheduler_settings,
|
return (GThread *) g_system_thread_new (proxy, stack_size, name, func, data, error);
|
||||||
name, func, data, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
g_thread_get_scheduler_settings (GThreadSchedulerSettings *scheduler_settings)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (scheduler_settings != NULL, FALSE);
|
|
||||||
|
|
||||||
return g_system_thread_get_scheduler_settings (scheduler_settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,9 +117,6 @@ static gint max_unused_threads = 2;
|
|||||||
static gint kill_unused_threads = 0;
|
static gint kill_unused_threads = 0;
|
||||||
static guint max_idle_time = 15 * 1000;
|
static guint max_idle_time = 15 * 1000;
|
||||||
|
|
||||||
static GThreadSchedulerSettings shared_thread_scheduler_settings;
|
|
||||||
static gboolean have_shared_thread_scheduler_settings = FALSE;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/* Either thread or error are set in the end. Both transfer-full. */
|
/* Either thread or error are set in the end. Both transfer-full. */
|
||||||
@ -471,30 +468,22 @@ g_thread_pool_start_thread (GRealThreadPool *pool,
|
|||||||
{
|
{
|
||||||
/* For non-exclusive thread-pools this can be called at any time
|
/* For non-exclusive thread-pools this can be called at any time
|
||||||
* when a new thread is needed. We make sure to create a new thread
|
* when a new thread is needed. We make sure to create a new thread
|
||||||
* here with the correct scheduler settings: either by directly
|
* here with the correct scheduler settings by going via our helper
|
||||||
* providing them if supported by the GThread implementation or by
|
* thread.
|
||||||
* going via our helper thread.
|
|
||||||
*/
|
*/
|
||||||
if (have_shared_thread_scheduler_settings)
|
SpawnThreadData spawn_thread_data = { (GThreadPool *) pool, NULL, NULL };
|
||||||
{
|
|
||||||
thread = g_thread_new_internal (name, g_thread_proxy, g_thread_pool_thread_proxy, pool, 0, &shared_thread_scheduler_settings, error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SpawnThreadData spawn_thread_data = { (GThreadPool *) pool, NULL, NULL };
|
|
||||||
|
|
||||||
g_async_queue_lock (spawn_thread_queue);
|
g_async_queue_lock (spawn_thread_queue);
|
||||||
|
|
||||||
g_async_queue_push_unlocked (spawn_thread_queue, &spawn_thread_data);
|
g_async_queue_push_unlocked (spawn_thread_queue, &spawn_thread_data);
|
||||||
|
|
||||||
while (!spawn_thread_data.thread && !spawn_thread_data.error)
|
while (!spawn_thread_data.thread && !spawn_thread_data.error)
|
||||||
g_cond_wait (&spawn_thread_cond, _g_async_queue_get_mutex (spawn_thread_queue));
|
g_cond_wait (&spawn_thread_cond, _g_async_queue_get_mutex (spawn_thread_queue));
|
||||||
|
|
||||||
thread = spawn_thread_data.thread;
|
thread = spawn_thread_data.thread;
|
||||||
if (!thread)
|
if (!thread)
|
||||||
g_propagate_error (error, g_steal_pointer (&spawn_thread_data.error));
|
g_propagate_error (error, g_steal_pointer (&spawn_thread_data.error));
|
||||||
g_async_queue_unlock (spawn_thread_queue);
|
g_async_queue_unlock (spawn_thread_queue);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread == NULL)
|
if (thread == NULL)
|
||||||
@ -547,6 +536,11 @@ g_thread_pool_start_thread (GRealThreadPool *pool,
|
|||||||
* since their threads are never considered idle and returned to the
|
* since their threads are never considered idle and returned to the
|
||||||
* global pool.
|
* global pool.
|
||||||
*
|
*
|
||||||
|
* Note that the threads used by exclusive threadpools will all inherit the
|
||||||
|
* scheduler settings of the current thread while the threads used by
|
||||||
|
* non-exclusive threadpools will inherit the scheduler settings from the
|
||||||
|
* first thread that created such a threadpool.
|
||||||
|
*
|
||||||
* @error can be %NULL to ignore errors, or non-%NULL to report
|
* @error can be %NULL to ignore errors, or non-%NULL to report
|
||||||
* errors. An error can only occur when @exclusive is set to %TRUE
|
* errors. An error can only occur when @exclusive is set to %TRUE
|
||||||
* and not all @max_threads threads could be created.
|
* and not all @max_threads threads could be created.
|
||||||
@ -620,43 +614,31 @@ g_thread_pool_new_full (GFunc func,
|
|||||||
if (!unused_thread_queue)
|
if (!unused_thread_queue)
|
||||||
unused_thread_queue = g_async_queue_new ();
|
unused_thread_queue = g_async_queue_new ();
|
||||||
|
|
||||||
/* For the very first non-exclusive thread-pool we remember the thread
|
/*
|
||||||
* scheduler settings of the thread creating the pool, if supported by
|
* Spawn a helper thread that is only responsible for spawning new threads
|
||||||
* the GThread implementation. This is then used for making sure that
|
* with the scheduler settings of the current thread.
|
||||||
* all threads created on the non-exclusive thread-pool have the same
|
*
|
||||||
* scheduler settings, and more importantly don't just inherit them
|
* This is then used for making sure that all threads created on the
|
||||||
* from the thread that just happened to push a new task and caused
|
* non-exclusive thread-pool have the same scheduler settings, and more
|
||||||
* a new thread to be created.
|
* importantly don't just inherit them from the thread that just happened to
|
||||||
|
* push a new task and caused a new thread to be created.
|
||||||
*
|
*
|
||||||
* Not doing so could cause real-time priority threads or otherwise
|
* Not doing so could cause real-time priority threads or otherwise
|
||||||
* threads with problematic scheduler settings to be part of the
|
* threads with problematic scheduler settings to be part of the
|
||||||
* non-exclusive thread-pools.
|
* non-exclusive thread-pools.
|
||||||
*
|
*
|
||||||
* If this is not supported by the GThread implementation then we here
|
* For exclusive thread-pools this is not required as all threads are
|
||||||
* start a thread that will inherit the scheduler settings from this
|
* created immediately below and are running forever, so they will
|
||||||
* very thread and whose only purpose is to spawn new threads with the
|
|
||||||
* same settings for use by the non-exclusive thread-pools.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* For non-exclusive thread-pools this is not required as all threads
|
|
||||||
* are created immediately below and are running forever, so they will
|
|
||||||
* automatically inherit the scheduler settings from this very thread.
|
* automatically inherit the scheduler settings from this very thread.
|
||||||
*/
|
*/
|
||||||
if (!exclusive && !have_shared_thread_scheduler_settings && !spawn_thread_queue)
|
if (!exclusive && !spawn_thread_queue)
|
||||||
{
|
{
|
||||||
if (g_thread_get_scheduler_settings (&shared_thread_scheduler_settings))
|
GThread *pool_spawner = NULL;
|
||||||
{
|
|
||||||
have_shared_thread_scheduler_settings = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GThread *pool_spawner = NULL;
|
|
||||||
|
|
||||||
spawn_thread_queue = g_async_queue_new ();
|
spawn_thread_queue = g_async_queue_new ();
|
||||||
g_cond_init (&spawn_thread_cond);
|
g_cond_init (&spawn_thread_cond);
|
||||||
pool_spawner = g_thread_new ("pool-spawner", g_thread_pool_spawn_thread, NULL);
|
pool_spawner = g_thread_new ("pool-spawner", g_thread_pool_spawn_thread, NULL);
|
||||||
g_ignore_leak (pool_spawner);
|
g_ignore_leak (pool_spawner);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
G_UNLOCK (init);
|
G_UNLOCK (init);
|
||||||
|
|
||||||
|
@ -90,25 +90,10 @@ struct _GRealThread
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Platform-specific scheduler settings for a thread */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
#if defined(HAVE_SYS_SCHED_GETATTR)
|
|
||||||
/* This is for modern Linux */
|
|
||||||
struct sched_attr *attr;
|
|
||||||
#elif defined(G_OS_WIN32)
|
|
||||||
gint thread_prio;
|
|
||||||
#else
|
|
||||||
/* TODO: Add support for macOS and the BSDs */
|
|
||||||
void *dummy;
|
|
||||||
#endif
|
|
||||||
} GThreadSchedulerSettings;
|
|
||||||
|
|
||||||
void g_system_thread_wait (GRealThread *thread);
|
void g_system_thread_wait (GRealThread *thread);
|
||||||
|
|
||||||
GRealThread *g_system_thread_new (GThreadFunc proxy,
|
GRealThread *g_system_thread_new (GThreadFunc proxy,
|
||||||
gulong stack_size,
|
gulong stack_size,
|
||||||
const GThreadSchedulerSettings *scheduler_settings,
|
|
||||||
const char *name,
|
const char *name,
|
||||||
GThreadFunc func,
|
GThreadFunc func,
|
||||||
gpointer data,
|
gpointer data,
|
||||||
@ -118,19 +103,14 @@ void g_system_thread_free (GRealThread *thread);
|
|||||||
void g_system_thread_exit (void);
|
void g_system_thread_exit (void);
|
||||||
void g_system_thread_set_name (const gchar *name);
|
void g_system_thread_set_name (const gchar *name);
|
||||||
|
|
||||||
gboolean g_system_thread_get_scheduler_settings (GThreadSchedulerSettings *scheduler_settings);
|
|
||||||
|
|
||||||
/* gthread.c */
|
/* gthread.c */
|
||||||
GThread *g_thread_new_internal (const gchar *name,
|
GThread *g_thread_new_internal (const gchar *name,
|
||||||
GThreadFunc proxy,
|
GThreadFunc proxy,
|
||||||
GThreadFunc func,
|
GThreadFunc func,
|
||||||
gpointer data,
|
gpointer data,
|
||||||
gsize stack_size,
|
gsize stack_size,
|
||||||
const GThreadSchedulerSettings *scheduler_settings,
|
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
gboolean g_thread_get_scheduler_settings (GThreadSchedulerSettings *scheduler_settings);
|
|
||||||
|
|
||||||
gpointer g_thread_proxy (gpointer thread);
|
gpointer g_thread_proxy (gpointer thread);
|
||||||
|
|
||||||
guint g_thread_n_created (void);
|
guint g_thread_n_created (void);
|
||||||
|
@ -1952,10 +1952,6 @@ else
|
|||||||
glib_conf.set('HAVE_PTHREAD_GETNAME_NP', 1)
|
glib_conf.set('HAVE_PTHREAD_GETNAME_NP', 1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if cc.has_header_symbol('sys/syscall.h', 'SYS_sched_getattr')
|
|
||||||
glib_conf.set('HAVE_SYS_SCHED_GETATTR', 1)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Assume that pthread_setname_np is available in some form; same as configure
|
# Assume that pthread_setname_np is available in some form; same as configure
|
||||||
if cc.links(pthread_prefix + '''
|
if cc.links(pthread_prefix + '''
|
||||||
int main() {
|
int main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user