mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
Merge branch 'threadpool-shared-thread-prios' into 'main'
GThreadPool: Always use the thread-spawning thread for the global shared thread pool Closes #2769 See merge request GNOME/glib!3208
This commit is contained in:
commit
ce876ab28b
@ -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);
|
||||||
|
@ -1956,10 +1956,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