Skip to content

Commit cd37d08

Browse files
committed
deps: cherry-pick libuv@e900006 and libuv@64669fd
Original commit log for libuv@e900006 follows: thread: add support for affinity (nodejs#3774) Backported thread affinity feature and related dependency commits from master. It will add support for those APIs: uv_cpumask_size, uv_thread_setaffinity, uv_thread_getaffinity. The supported platforms are Linux, Freebsd, and Windows. Empty implementations (returning UV_ENOTSUP) on non-supported platforms (such as OS X and AIX). Original commit log for libuv@64669fd follows: thread: add uv_thread_getcpu() (nodejs#3803) Add uv_thread_getcpu() api to get the cpu number on which the calling thread is running.
1 parent ccd3a42 commit cd37d08

File tree

11 files changed

+398
-0
lines changed

11 files changed

+398
-0
lines changed

deps/uv/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ if(LIBUV_BUILD_TESTS)
592592
test/test-tcp-write-to-half-open-connection.c
593593
test/test-tcp-writealot.c
594594
test/test-test-macros.c
595+
test/test-thread-affinity.c
595596
test/test-thread-equal.c
596597
test/test-thread.c
597598
test/test-threadpool-cancel.c

deps/uv/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
283283
test/test-test-macros.c \
284284
test/test-thread-equal.c \
285285
test/test-thread.c \
286+
test/test-thread-affinity.c \
286287
test/test-threadpool-cancel.c \
287288
test/test-threadpool.c \
288289
test/test-timer-again.c \

deps/uv/docs/src/misc.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,13 @@ API
362362
363363
Frees the `cpu_infos` array previously allocated with :c:func:`uv_cpu_info`.
364364
365+
.. c:function:: int uv_cpumask_size(void)
366+
367+
Returns the maximum size of the mask used for process/thread affinities,
368+
or ``UV_ENOTSUP`` if affinities are not supported on the current platform.
369+
370+
.. versionadded:: 1.45.0
371+
365372
.. c:function:: int uv_interface_addresses(uv_interface_address_t** addresses, int* count)
366373
367374
Gets address information about the network interfaces on the system. An

deps/uv/docs/src/threading.rst

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,46 @@ Threads
8888
8989
.. versionadded:: 1.26.0
9090
91+
.. c:function:: int uv_thread_setaffinity(uv_thread_t* tid, char* cpumask, char* oldmask, size_t mask_size)
92+
93+
Sets the specified thread's affinity to cpumask, which is specified in
94+
bytes. Optionally returning the previous affinity setting in oldmask.
95+
On Unix, uses :man:`pthread_getaffinity_np(3)` to get the affinity setting
96+
and maps the cpu_set_t to bytes in oldmask. Then maps the bytes in cpumask
97+
to a cpu_set_t and uses :man:`pthread_setaffinity_np(3)`. On Windows, maps
98+
the bytes in cpumask to a bitmask and uses SetThreadAffinityMask() which
99+
returns the previous affinity setting.
100+
101+
The mask_size specifies the number of entries (bytes) in cpumask / oldmask,
102+
and must be greater-than-or-equal-to :c:func:`uv_cpumask_size`.
103+
104+
.. note::
105+
Thread affinity setting is not atomic on Windows. Unsupported on macOS.
106+
107+
.. versionadded:: 1.45.0
108+
109+
.. c:function:: int uv_thread_getaffinity(uv_thread_t* tid, char* cpumask, size_t mask_size)
110+
111+
Gets the specified thread's affinity setting. On Unix, this maps the
112+
cpu_set_t returned by :man:`pthread_getaffinity_np(3)` to bytes in cpumask.
113+
114+
The mask_size specifies the number of entries (bytes) in cpumask,
115+
and must be greater-than-or-equal-to :c:func:`uv_cpumask_size`.
116+
117+
.. note::
118+
Thread affinity getting is not atomic on Windows. Unsupported on macOS.
119+
120+
.. versionadded:: 1.45.0
121+
122+
.. c:function:: int uv_thread_getcpu(void)
123+
124+
Gets the CPU number on which the calling thread is running.
125+
126+
.. note::
127+
Currently only implemented on Windows, Linux and FreeBSD.
128+
129+
.. versionadded:: 1.45.0
130+
91131
.. c:function:: uv_thread_t uv_thread_self(void)
92132
.. c:function:: int uv_thread_join(uv_thread_t *tid)
93133
.. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2)

deps/uv/include/uv.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,7 @@ UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
12451245
UV_EXTERN unsigned int uv_available_parallelism(void);
12461246
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
12471247
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
1248+
UV_EXTERN int uv_cpumask_size(void);
12481249

12491250
UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
12501251
int* count);
@@ -1787,6 +1788,14 @@ UV_EXTERN int uv_thread_create_ex(uv_thread_t* tid,
17871788
const uv_thread_options_t* params,
17881789
uv_thread_cb entry,
17891790
void* arg);
1791+
UV_EXTERN int uv_thread_setaffinity(uv_thread_t* tid,
1792+
char* cpumask,
1793+
char* oldmask,
1794+
size_t mask_size);
1795+
UV_EXTERN int uv_thread_getaffinity(uv_thread_t* tid,
1796+
char* cpumask,
1797+
size_t mask_size);
1798+
UV_EXTERN int uv_thread_getcpu(void);
17901799
UV_EXTERN uv_thread_t uv_thread_self(void);
17911800
UV_EXTERN int uv_thread_join(uv_thread_t *tid);
17921801
UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);

deps/uv/src/unix/core.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ extern char** environ;
7272
# include <sys/sysctl.h>
7373
# include <sys/filio.h>
7474
# include <sys/wait.h>
75+
# include <sys/param.h>
76+
# include <sys/cpuset.h>
7577
# if defined(__FreeBSD__)
7678
# define uv__accept4 accept4
7779
# endif
@@ -1416,6 +1418,13 @@ uv_pid_t uv_os_getppid(void) {
14161418
return getppid();
14171419
}
14181420

1421+
int uv_cpumask_size(void) {
1422+
#if defined(__linux__) || defined(__FreeBSD__)
1423+
return CPU_SETSIZE;
1424+
#else
1425+
return UV_ENOTSUP;
1426+
#endif
1427+
}
14191428

14201429
int uv_os_getpriority(uv_pid_t pid, int* priority) {
14211430
int r;

deps/uv/src/unix/thread.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@
4141
#include <gnu/libc-version.h> /* gnu_get_libc_version() */
4242
#endif
4343

44+
#if defined(__linux__)
45+
# include <sched.h>
46+
# define uv__cpu_set_t cpu_set_t
47+
#elif defined(__FreeBSD__)
48+
# include <sys/param.h>
49+
# include <sys/cpuset.h>
50+
# include <pthread_np.h>
51+
# define uv__cpu_set_t cpuset_t
52+
#endif
53+
54+
4455
#undef NANOSEC
4556
#define NANOSEC ((uint64_t) 1e9)
4657

@@ -284,6 +295,106 @@ int uv_thread_create_ex(uv_thread_t* tid,
284295
return UV__ERR(err);
285296
}
286297

298+
#if defined(__linux__) || defined(__FreeBSD__)
299+
300+
int uv_thread_setaffinity(uv_thread_t* tid,
301+
char* cpumask,
302+
char* oldmask,
303+
size_t mask_size) {
304+
int i;
305+
int r;
306+
uv__cpu_set_t cpuset;
307+
int cpumasksize;
308+
309+
cpumasksize = uv_cpumask_size();
310+
if (cpumasksize < 0)
311+
return cpumasksize;
312+
if (mask_size < (size_t)cpumasksize)
313+
return UV_EINVAL;
314+
315+
if (oldmask != NULL) {
316+
r = uv_thread_getaffinity(tid, oldmask, mask_size);
317+
if (r < 0)
318+
return r;
319+
}
320+
321+
CPU_ZERO(&cpuset);
322+
for (i = 0; i < cpumasksize; i++)
323+
if (cpumask[i])
324+
CPU_SET(i, &cpuset);
325+
326+
#if defined(__ANDROID__)
327+
if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
328+
r = errno;
329+
else
330+
r = 0;
331+
#else
332+
r = pthread_setaffinity_np(*tid, sizeof(cpuset), &cpuset);
333+
#endif
334+
335+
return UV__ERR(r);
336+
}
337+
338+
339+
int uv_thread_getaffinity(uv_thread_t* tid,
340+
char* cpumask,
341+
size_t mask_size) {
342+
int r;
343+
int i;
344+
uv__cpu_set_t cpuset;
345+
int cpumasksize;
346+
347+
cpumasksize = uv_cpumask_size();
348+
if (cpumasksize < 0)
349+
return cpumasksize;
350+
if (mask_size < (size_t)cpumasksize)
351+
return UV_EINVAL;
352+
353+
CPU_ZERO(&cpuset);
354+
#if defined(__ANDROID__)
355+
if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset))
356+
r = errno;
357+
else
358+
r = 0;
359+
#else
360+
r = pthread_getaffinity_np(*tid, sizeof(cpuset), &cpuset);
361+
#endif
362+
if (r)
363+
return UV__ERR(r);
364+
for (i = 0; i < cpumasksize; i++)
365+
cpumask[i] = !!CPU_ISSET(i, &cpuset);
366+
367+
return 0;
368+
}
369+
#else
370+
int uv_thread_setaffinity(uv_thread_t* tid,
371+
char* cpumask,
372+
char* oldmask,
373+
size_t mask_size) {
374+
return UV_ENOTSUP;
375+
}
376+
377+
378+
int uv_thread_getaffinity(uv_thread_t* tid,
379+
char* cpumask,
380+
size_t mask_size) {
381+
return UV_ENOTSUP;
382+
}
383+
#endif /* defined(__linux__) || defined(UV_BSD_H) */
384+
385+
int uv_thread_getcpu(void) {
386+
#if defined(__linux__) || defined(__FreeBSD__)
387+
int cpu;
388+
389+
cpu = sched_getcpu();
390+
if (cpu < 0)
391+
return UV__ERR(errno);
392+
393+
return cpu;
394+
#else
395+
return UV_ENOTSUP;
396+
#endif
397+
}
287398

288399
uv_thread_t uv_thread_self(void) {
289400
return pthread_self();

deps/uv/src/win/thread.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,81 @@ int uv_thread_create_ex(uv_thread_t* tid,
180180
return UV_EIO;
181181
}
182182

183+
int uv_thread_setaffinity(uv_thread_t* tid,
184+
char* cpumask,
185+
char* oldmask,
186+
size_t mask_size) {
187+
int i;
188+
HANDLE hproc;
189+
DWORD_PTR procmask;
190+
DWORD_PTR sysmask;
191+
DWORD_PTR threadmask;
192+
DWORD_PTR oldthreadmask;
193+
int cpumasksize;
194+
195+
cpumasksize = uv_cpumask_size();
196+
assert(cpumasksize > 0);
197+
if (mask_size < (size_t)cpumasksize)
198+
return UV_EINVAL;
199+
200+
hproc = GetCurrentProcess();
201+
if (!GetProcessAffinityMask(hproc, &procmask, &sysmask))
202+
return uv_translate_sys_error(GetLastError());
203+
204+
threadmask = 0;
205+
for (i = 0; i < cpumasksize; i++) {
206+
if (cpumask[i]) {
207+
if (procmask & (1 << i))
208+
threadmask |= 1 << i;
209+
else
210+
return UV_EINVAL;
211+
}
212+
}
213+
214+
oldthreadmask = SetThreadAffinityMask(*tid, threadmask);
215+
if (oldthreadmask == 0)
216+
return uv_translate_sys_error(GetLastError());
217+
218+
if (oldmask != NULL) {
219+
for (i = 0; i < cpumasksize; i++)
220+
oldmask[i] = (oldthreadmask >> i) & 1;
221+
}
222+
223+
return 0;
224+
}
225+
226+
int uv_thread_getaffinity(uv_thread_t* tid,
227+
char* cpumask,
228+
size_t mask_size) {
229+
int i;
230+
HANDLE hproc;
231+
DWORD_PTR procmask;
232+
DWORD_PTR sysmask;
233+
DWORD_PTR threadmask;
234+
int cpumasksize;
235+
236+
cpumasksize = uv_cpumask_size();
237+
assert(cpumasksize > 0);
238+
if (mask_size < (size_t)cpumasksize)
239+
return UV_EINVAL;
240+
241+
hproc = GetCurrentProcess();
242+
if (!GetProcessAffinityMask(hproc, &procmask, &sysmask))
243+
return uv_translate_sys_error(GetLastError());
244+
245+
threadmask = SetThreadAffinityMask(*tid, procmask);
246+
if (threadmask == 0 || SetThreadAffinityMask(*tid, threadmask) == 0)
247+
return uv_translate_sys_error(GetLastError());
248+
249+
for (i = 0; i < cpumasksize; i++)
250+
cpumask[i] = (threadmask >> i) & 1;
251+
252+
return 0;
253+
}
254+
255+
int uv_thread_getcpu(void) {
256+
return GetCurrentProcessorNumber();
257+
}
183258

184259
uv_thread_t uv_thread_self(void) {
185260
uv_thread_t key;

deps/uv/test/task.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,4 +375,11 @@ UNUSED static int can_ipv6(void) {
375375
"Cygwin runtime hangs on listen+connect in same process."
376376
#endif
377377

378+
#if !defined(__linux__) && \
379+
!defined(__FreeBSD__) && \
380+
!defined(_WIN32)
381+
# define NO_CPU_AFFINITY \
382+
"affinity not supported on this platform."
383+
#endif
384+
378385
#endif /* TASK_H_ */

deps/uv/test/test-list.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ TEST_DECLARE (thread_rwlock)
448448
TEST_DECLARE (thread_rwlock_trylock)
449449
TEST_DECLARE (thread_create)
450450
TEST_DECLARE (thread_equal)
451+
TEST_DECLARE (thread_affinity)
451452
TEST_DECLARE (dlerror)
452453
#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \
453454
!defined(__sun)
@@ -1118,6 +1119,7 @@ TASK_LIST_START
11181119
TEST_ENTRY (thread_rwlock_trylock)
11191120
TEST_ENTRY (thread_create)
11201121
TEST_ENTRY (thread_equal)
1122+
TEST_ENTRY (thread_affinity)
11211123
TEST_ENTRY (dlerror)
11221124
TEST_ENTRY (ip4_addr)
11231125
TEST_ENTRY (ip6_addr_link_local)

0 commit comments

Comments
 (0)