Skip to content

Commit

Permalink
unix,win: add uv_os_{get,set}priority()
Browse files Browse the repository at this point in the history
Refs: nodejs/node#21675
PR-URL: libuv#1945
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
  • Loading branch information
cjihrig committed Aug 15, 2018
1 parent 7284adf commit 81c7742
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ set(uv_test_sources
test/test-poll-closesocket.c
test/test-poll-oob.c
test/test-poll.c
test/test-process-priority.c
test/test-process-title-threadsafe.c
test/test-process-title.c
test/test-queue-foreach-delete.c
Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-poll-close-doesnt-corrupt-stack.c \
test/test-poll-closesocket.c \
test/test-poll-oob.c \
test/test-process-priority.c \
test/test-process-title.c \
test/test-process-title-threadsafe.c \
test/test-queue-foreach-delete.c \
Expand Down
28 changes: 28 additions & 0 deletions docs/src/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,31 @@ API
storage required to hold the value.
.. versionadded:: 1.12.0
.. c:function:: int uv_os_getpriority(uv_pid_t pid, int* priority)
Retrieves the scheduling priority of the process specified by `pid`. The
returned value of `priority` is between -20 (high priority) and 19 (low
priority).
.. note::
On Windows, the returned priority will equal one of the `UV_PRIORITY`
constants.
.. versionadded:: REPLACEME
.. c:function:: int uv_os_setpriority(uv_pid_t pid, int priority)
Sets the scheduling priority of the process specified by `pid`. The
`priority` value range is between -20 (high priority) and 19 (low priority).
The constants `UV_PRIORITY_LOW`, `UV_PRIORITY_BELOW_NORMAL`,
`UV_PRIORITY_NORMAL`, `UV_PRIORITY_ABOVE_NORMAL`, `UV_PRIORITY_HIGH`, and
`UV_PRIORITY_HIGHEST` are also provided for convenience.
.. note::
On Windows, this function utilizes `SetPriorityClass()`. The `priority`
argument is mapped to a Windows priority class. When retrieving the
process priority, the result will equal one of the `UV_PRIORITY`
constants, and not necessarily the exact value of `priority`.
.. versionadded:: REPLACEME
10 changes: 10 additions & 0 deletions include/uv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,16 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
UV_EXTERN uv_pid_t uv_os_getpid(void);
UV_EXTERN uv_pid_t uv_os_getppid(void);

#define UV_PRIORITY_LOW 19
#define UV_PRIORITY_BELOW_NORMAL 10
#define UV_PRIORITY_NORMAL 0
#define UV_PRIORITY_ABOVE_NORMAL -7
#define UV_PRIORITY_HIGH -14
#define UV_PRIORITY_HIGHEST -20

UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);

UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);

Expand Down
28 changes: 28 additions & 0 deletions src/unix/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1350,3 +1350,31 @@ uv_pid_t uv_os_getpid(void) {
uv_pid_t uv_os_getppid(void) {
return getppid();
}


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

if (priority == NULL)
return UV_EINVAL;

errno = 0;
r = getpriority(PRIO_PROCESS, (int) pid);

if (r == -1 && errno != 0)
return UV__ERR(errno);

*priority = r;
return 0;
}


int uv_os_setpriority(uv_pid_t pid, int priority) {
if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
return UV_EINVAL;

if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0)
return UV__ERR(errno);

return 0;
}
94 changes: 94 additions & 0 deletions src/win/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1530,3 +1530,97 @@ int uv_os_gethostname(char* buffer, size_t* size) {
*size = len;
return 0;
}


static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
int r;

if (pid == 0)
*handle = GetCurrentProcess();
else
*handle = OpenProcess(access, FALSE, pid);

if (*handle == NULL) {
r = GetLastError();

if (r == ERROR_INVALID_PARAMETER)
return UV_ESRCH;
else
return uv_translate_sys_error(r);
}

return 0;
}


int uv_os_getpriority(uv_pid_t pid, int* priority) {
HANDLE handle;
int r;

if (priority == NULL)
return UV_EINVAL;

r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);

if (r != 0)
return r;

r = GetPriorityClass(handle);

if (r == 0) {
r = uv_translate_sys_error(GetLastError());
} else {
/* Map Windows priority classes to Unix nice values. */
if (r == REALTIME_PRIORITY_CLASS)
*priority = UV_PRIORITY_HIGHEST;
else if (r == HIGH_PRIORITY_CLASS)
*priority = UV_PRIORITY_HIGH;
else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
*priority = UV_PRIORITY_ABOVE_NORMAL;
else if (r == NORMAL_PRIORITY_CLASS)
*priority = UV_PRIORITY_NORMAL;
else if (r == BELOW_NORMAL_PRIORITY_CLASS)
*priority = UV_PRIORITY_BELOW_NORMAL;
else /* IDLE_PRIORITY_CLASS */
*priority = UV_PRIORITY_LOW;

r = 0;
}

CloseHandle(handle);
return r;
}


int uv_os_setpriority(uv_pid_t pid, int priority) {
HANDLE handle;
int priority_class;
int r;

/* Map Unix nice values to Windows priority classes. */
if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
return UV_EINVAL;
else if (priority < UV_PRIORITY_HIGH)
priority_class = REALTIME_PRIORITY_CLASS;
else if (priority < UV_PRIORITY_ABOVE_NORMAL)
priority_class = HIGH_PRIORITY_CLASS;
else if (priority < UV_PRIORITY_NORMAL)
priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
else if (priority < UV_PRIORITY_BELOW_NORMAL)
priority_class = NORMAL_PRIORITY_CLASS;
else if (priority < UV_PRIORITY_LOW)
priority_class = BELOW_NORMAL_PRIORITY_CLASS;
else
priority_class = IDLE_PRIORITY_CLASS;

r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);

if (r != 0)
return r;

if (SetPriorityClass(handle, priority_class) == 0)
r = uv_translate_sys_error(GetLastError());

CloseHandle(handle);
return r;
}
2 changes: 2 additions & 0 deletions test/test-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ TEST_DECLARE (pipe_close_stdout_read_stdin)
TEST_DECLARE (pipe_set_non_blocking)
TEST_DECLARE (pipe_set_chmod)
TEST_DECLARE (process_ref)
TEST_DECLARE (process_priority)
TEST_DECLARE (has_ref)
TEST_DECLARE (active)
TEST_DECLARE (embed)
Expand Down Expand Up @@ -689,6 +690,7 @@ TASK_LIST_START
TEST_ENTRY (pipe_ref4)
TEST_HELPER (pipe_ref4, pipe_echo_server)
TEST_ENTRY (process_ref)
TEST_ENTRY (process_priority)
TEST_ENTRY (has_ref)

TEST_ENTRY (loop_handles)
Expand Down
81 changes: 81 additions & 0 deletions test/test-process-priority.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* Copyright libuv contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#include "uv.h"
#include "task.h"


TEST_IMPL(process_priority) {
int priority;
int r;
int i;

#if defined(__MVS__)
if (uv_os_setpriority(0, 0) == UV_ENOSYS)
RETURN_SKIP("functionality not supported on zOS");
#endif

/* Verify that passing a NULL pointer returns UV_EINVAL. */
r = uv_os_getpriority(0, NULL);
ASSERT(r == UV_EINVAL);

/* Verify that all valid values work. */
for (i = UV_PRIORITY_HIGHEST; i <= UV_PRIORITY_LOW; i++) {
r = uv_os_setpriority(0, i);

/* If UV_EACCES is returned, the current user doesn't have permission to
set this specific priority. */
if (r == UV_EACCES)
continue;

ASSERT(r == 0);
ASSERT(uv_os_getpriority(0, &priority) == 0);

/* Verify that the priority values match on Unix, and are range mapped
on Windows. */
#ifndef _WIN32
ASSERT(priority == i);
#else
if (i < UV_PRIORITY_HIGH)
ASSERT(priority == UV_PRIORITY_HIGHEST);
else if (i < UV_PRIORITY_ABOVE_NORMAL)
ASSERT(priority == UV_PRIORITY_HIGH);
else if (i < UV_PRIORITY_NORMAL)
ASSERT(priority == UV_PRIORITY_ABOVE_NORMAL);
else if (i < UV_PRIORITY_BELOW_NORMAL)
ASSERT(priority == UV_PRIORITY_NORMAL);
else if (i < UV_PRIORITY_LOW)
ASSERT(priority == UV_PRIORITY_BELOW_NORMAL);
else
ASSERT(priority == UV_PRIORITY_LOW);
#endif

/* Verify that the current PID and 0 are equivalent. */
ASSERT(uv_os_getpriority(uv_os_getpid(), &r) == 0);
ASSERT(priority == r);
}

/* Verify that invalid priorities return UV_EINVAL. */
ASSERT(uv_os_setpriority(0, UV_PRIORITY_HIGHEST - 1) == UV_EINVAL);
ASSERT(uv_os_setpriority(0, UV_PRIORITY_LOW + 1) == UV_EINVAL);

return 0;
}
1 change: 1 addition & 0 deletions test/test.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
'test-poll-close-doesnt-corrupt-stack.c',
'test-poll-closesocket.c',
'test-poll-oob.c',
'test-process-priority.c',
'test-process-title.c',
'test-process-title-threadsafe.c',
'test-queue-foreach-delete.c',
Expand Down

0 comments on commit 81c7742

Please sign in to comment.