summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/os.md87
-rw-r--r--lib/constants.js1
-rw-r--r--lib/os.js37
-rw-r--r--src/node_constants.cc44
-rw-r--r--src/node_os.cc43
-rw-r--r--test/parallel/test-binding-constants.js2
-rw-r--r--test/parallel/test-os-process-priority.js131
7 files changed, 343 insertions, 2 deletions
diff --git a/doc/api/os.md b/doc/api/os.md
index b7bd246f97..4557bb6b7d 100644
--- a/doc/api/os.md
+++ b/doc/api/os.md
@@ -192,6 +192,19 @@ added: v0.3.3
The `os.freemem()` method returns the amount of free system memory in bytes as
an integer.
+## os.getPriority([pid])
+<!-- YAML
+added: REPLACEME
+-->
+
+* `pid` {integer} The process ID to retrieve scheduling priority for.
+ **Default** `0`.
+* Returns: {integer}
+
+The `os.getPriority()` method returns the scheduling priority for the process
+specified by `pid`. If `pid` is not provided, or is `0`, the priority of the
+current process is returned.
+
## os.homedir()
<!-- YAML
added: v2.3.0
@@ -338,6 +351,26 @@ On POSIX systems, the operating system release is determined by calling
[uname(3)][]. On Windows, `GetVersionExW()` is used. Please see
https://en.wikipedia.org/wiki/Uname#Examples for more information.
+## os.setPriority([pid, ]priority)
+<!-- YAML
+added: REPLACEME
+-->
+
+* `pid` {integer} The process ID to set scheduling priority for.
+ **Default** `0`.
+* `priority` {integer} The scheduling priority to assign to the process.
+
+The `os.setPriority()` method attempts to set the scheduling priority for the
+process specified by `pid`. If `pid` is not provided, or is `0`, the priority
+of the current process is used.
+
+The `priority` input must be an integer between `-20` (high priority) and `19`
+(low priority). Due to differences between Unix priority levels and Windows
+priority classes, `priority` is mapped to one of six priority constants in
+`os.constants.priority`. When retrieving a process priority level, this range
+mapping may cause the return value to be slightly different on Windows. To avoid
+confusion, it is recommended to set `priority` to one of the priority constants.
+
## os.tmpdir()
<!-- YAML
added: v0.9.9
@@ -1208,6 +1241,60 @@ information.
</tr>
</table>
+### Priority Constants
+<!-- YAML
+added: REPLACEME
+-->
+
+The following process scheduling constants are exported by
+`os.constants.priority`:
+
+<table>
+ <tr>
+ <th>Constant</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><code>PRIORITY_LOW</code></td>
+ <td>The lowest process scheduling priority. This corresponds to
+ <code>IDLE_PRIORITY_CLASS</code> on Windows, and a nice value of
+ <code>19</code> on all other platforms.</td>
+ </tr>
+ <tr>
+ <td><code>PRIORITY_BELOW_NORMAL</code></td>
+ <td>The process scheduling priority above <code>PRIORITY_LOW</code> and
+ below <code>PRIORITY_NORMAL</code>. This corresponds to
+ <code>BELOW_NORMAL_PRIORITY_CLASS</code> on Windows, and a nice value of
+ <code>10</code> on all other platforms.</td>
+ </tr>
+ <tr>
+ <td><code>PRIORITY_NORMAL</code></td>
+ <td>The default process scheduling priority. This corresponds to
+ <code>NORMAL_PRIORITY_CLASS</code> on Windows, and a nice value of
+ <code>0</code> on all other platforms.</td>
+ </tr>
+ <tr>
+ <td><code>PRIORITY_ABOVE_NORMAL</code></td>
+ <td>The process scheduling priority above <code>PRIORITY_NORMAL</code> and
+ below <code>PRIORITY_HIGH</code>. This corresponds to
+ <code>ABOVE_NORMAL_PRIORITY_CLASS</code> on Windows, and a nice value of
+ <code>-7</code> on all other platforms.</td>
+ </tr>
+ <tr>
+ <td><code>PRIORITY_HIGH</code></td>
+ <td>The process scheduling priority above <code>PRIORITY_ABOVE_NORMAL</code>
+ and below <code>PRIORITY_HIGHEST</code>. This corresponds to
+ <code>HIGH_PRIORITY_CLASS</code> on Windows, and a nice value of
+ <code>-14</code> on all other platforms.</td>
+ </tr>
+ <tr>
+ <td><code>PRIORITY_HIGHEST</code></td>
+ <td>The highest process scheduling priority. This corresponds to
+ <code>REALTIME_PRIORITY_CLASS</code> on Windows, and a nice value of
+ <code>-20</code> on all other platforms.</td>
+ </tr>
+</table>
+
### libuv Constants
<table>
diff --git a/lib/constants.js b/lib/constants.js
index dee4612644..a4c2ca6fb3 100644
--- a/lib/constants.js
+++ b/lib/constants.js
@@ -29,6 +29,7 @@ const constants = process.binding('constants');
Object.assign(exports,
constants.os.dlopen,
constants.os.errno,
+ constants.os.priority,
constants.os.signals,
constants.fs,
constants.crypto);
diff --git a/lib/os.js b/lib/os.js
index 15d06f1576..09a70d2f7b 100644
--- a/lib/os.js
+++ b/lib/os.js
@@ -27,6 +27,7 @@ const { deprecate } = require('internal/util');
const isWindows = process.platform === 'win32';
const { codes: { ERR_SYSTEM_ERROR } } = require('internal/errors');
+const { validateInt32 } = require('internal/validators');
const {
getCPUs,
@@ -37,10 +38,12 @@ const {
getLoadAvg,
getOSRelease: _getOSRelease,
getOSType: _getOSType,
+ getPriority: _getPriority,
getTotalMem,
getUserInfo: _getUserInfo,
getUptime,
- isBigEndian
+ isBigEndian,
+ setPriority: _setPriority
} = process.binding('os');
function getCheckedFunction(fn) {
@@ -206,17 +209,49 @@ function networkInterfaces() {
return interfaceAddresses;
}
+function setPriority(pid, priority) {
+ if (priority === undefined) {
+ priority = pid;
+ pid = 0;
+ }
+
+ validateInt32(pid, 'pid');
+ validateInt32(priority, 'priority', -20, 19);
+
+ const ctx = {};
+
+ if (_setPriority(pid, priority, ctx) !== 0)
+ throw new ERR_SYSTEM_ERROR(ctx);
+}
+
+function getPriority(pid) {
+ if (pid === undefined)
+ pid = 0;
+ else
+ validateInt32(pid, 'pid');
+
+ const ctx = {};
+ const priority = _getPriority(pid, ctx);
+
+ if (priority === undefined)
+ throw new ERR_SYSTEM_ERROR(ctx);
+
+ return priority;
+}
+
module.exports = {
arch,
cpus,
endianness,
freemem: getFreeMem,
+ getPriority,
homedir: getHomeDirectory,
hostname: getHostname,
loadavg,
networkInterfaces,
platform,
release: getOSRelease,
+ setPriority,
tmpdir,
totalmem: getTotalMem,
type: getOSType,
diff --git a/src/node_constants.cc b/src/node_constants.cc
index 28d5a9ca4e..f1468ff7ca 100644
--- a/src/node_constants.cc
+++ b/src/node_constants.cc
@@ -758,6 +758,44 @@ void DefineSignalConstants(Local<Object> target) {
#endif
}
+void DefinePriorityConstants(Local<Object> target) {
+#ifdef UV_PRIORITY_LOW
+# define PRIORITY_LOW UV_PRIORITY_LOW
+ NODE_DEFINE_CONSTANT(target, PRIORITY_LOW);
+# undef PRIORITY_LOW
+#endif
+
+#ifdef UV_PRIORITY_BELOW_NORMAL
+# define PRIORITY_BELOW_NORMAL UV_PRIORITY_BELOW_NORMAL
+ NODE_DEFINE_CONSTANT(target, PRIORITY_BELOW_NORMAL);
+# undef PRIORITY_BELOW_NORMAL
+#endif
+
+#ifdef UV_PRIORITY_NORMAL
+# define PRIORITY_NORMAL UV_PRIORITY_NORMAL
+ NODE_DEFINE_CONSTANT(target, PRIORITY_NORMAL);
+# undef PRIORITY_NORMAL
+#endif
+
+#ifdef UV_PRIORITY_ABOVE_NORMAL
+# define PRIORITY_ABOVE_NORMAL UV_PRIORITY_ABOVE_NORMAL
+ NODE_DEFINE_CONSTANT(target, PRIORITY_ABOVE_NORMAL);
+# undef PRIORITY_ABOVE_NORMAL
+#endif
+
+#ifdef UV_PRIORITY_HIGH
+# define PRIORITY_HIGH UV_PRIORITY_HIGH
+ NODE_DEFINE_CONSTANT(target, PRIORITY_HIGH);
+# undef PRIORITY_HIGH
+#endif
+
+#ifdef UV_PRIORITY_HIGHEST
+# define PRIORITY_HIGHEST UV_PRIORITY_HIGHEST
+ NODE_DEFINE_CONSTANT(target, PRIORITY_HIGHEST);
+# undef PRIORITY_HIGHEST
+#endif
+}
+
void DefineOpenSSLConstants(Local<Object> target) {
#ifdef OPENSSL_VERSION_NUMBER
NODE_DEFINE_CONSTANT(target, OPENSSL_VERSION_NUMBER);
@@ -1338,6 +1376,10 @@ void DefineConstants(v8::Isolate* isolate, Local<Object> target) {
CHECK(sig_constants->SetPrototype(env->context(),
Null(env->isolate())).FromJust());
+ Local<Object> priority_constants = Object::New(isolate);
+ CHECK(priority_constants->SetPrototype(env->context(),
+ Null(env->isolate())).FromJust());
+
Local<Object> fs_constants = Object::New(isolate);
CHECK(fs_constants->SetPrototype(env->context(),
Null(env->isolate())).FromJust());
@@ -1361,6 +1403,7 @@ void DefineConstants(v8::Isolate* isolate, Local<Object> target) {
DefineErrnoConstants(err_constants);
DefineWindowsErrorConstants(err_constants);
DefineSignalConstants(sig_constants);
+ DefinePriorityConstants(priority_constants);
DefineSystemConstants(fs_constants);
DefineOpenSSLConstants(crypto_constants);
DefineCryptoConstants(crypto_constants);
@@ -1374,6 +1417,7 @@ void DefineConstants(v8::Isolate* isolate, Local<Object> target) {
os_constants->Set(OneByteString(isolate, "dlopen"), dlopen_constants);
os_constants->Set(OneByteString(isolate, "errno"), err_constants);
os_constants->Set(OneByteString(isolate, "signals"), sig_constants);
+ os_constants->Set(OneByteString(isolate, "priority"), priority_constants);
target->Set(OneByteString(isolate, "os"), os_constants);
target->Set(OneByteString(isolate, "fs"), fs_constants);
target->Set(OneByteString(isolate, "crypto"), crypto_constants);
diff --git a/src/node_os.cc b/src/node_os.cc
index c9eef808b0..d3e9460f47 100644
--- a/src/node_os.cc
+++ b/src/node_os.cc
@@ -52,6 +52,7 @@ using v8::Context;
using v8::Float64Array;
using v8::Function;
using v8::FunctionCallbackInfo;
+using v8::Int32;
using v8::Integer;
using v8::Local;
using v8::MaybeLocal;
@@ -405,6 +406,46 @@ static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
}
+static void SetPriority(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+
+ CHECK_EQ(args.Length(), 3);
+ CHECK(args[0]->IsInt32());
+ CHECK(args[1]->IsInt32());
+
+ const int pid = args[0].As<Int32>()->Value();
+ const int priority = args[1].As<Int32>()->Value();
+ const int err = uv_os_setpriority(pid, priority);
+
+ if (err) {
+ CHECK(args[2]->IsObject());
+ env->CollectUVExceptionInfo(args[2], err, "uv_os_setpriority");
+ }
+
+ args.GetReturnValue().Set(err);
+}
+
+
+static void GetPriority(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+
+ CHECK_EQ(args.Length(), 2);
+ CHECK(args[0]->IsInt32());
+
+ const int pid = args[0].As<Int32>()->Value();
+ int priority;
+ const int err = uv_os_getpriority(pid, &priority);
+
+ if (err) {
+ CHECK(args[1]->IsObject());
+ env->CollectUVExceptionInfo(args[1], err, "uv_os_getpriority");
+ return;
+ }
+
+ args.GetReturnValue().Set(priority);
+}
+
+
void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
@@ -420,6 +461,8 @@ void Initialize(Local<Object> target,
env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses);
env->SetMethod(target, "getHomeDirectory", GetHomeDirectory);
env->SetMethod(target, "getUserInfo", GetUserInfo);
+ env->SetMethod(target, "setPriority", SetPriority);
+ env->SetMethod(target, "getPriority", GetPriority);
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"),
Boolean::New(env->isolate(), IsBigEndian()));
}
diff --git a/test/parallel/test-binding-constants.js b/test/parallel/test-binding-constants.js
index b8e852b352..9855af1942 100644
--- a/test/parallel/test-binding-constants.js
+++ b/test/parallel/test-binding-constants.js
@@ -10,7 +10,7 @@ assert.deepStrictEqual(
assert.deepStrictEqual(
Object.keys(constants.os).sort(), ['UV_UDP_REUSEADDR', 'dlopen', 'errno',
- 'signals']
+ 'priority', 'signals']
);
// Make sure all the constants objects don't inherit from Object.prototype
diff --git a/test/parallel/test-os-process-priority.js b/test/parallel/test-os-process-priority.js
new file mode 100644
index 0000000000..9d66cfc49b
--- /dev/null
+++ b/test/parallel/test-os-process-priority.js
@@ -0,0 +1,131 @@
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const os = require('os');
+const {
+ PRIORITY_LOW,
+ PRIORITY_BELOW_NORMAL,
+ PRIORITY_NORMAL,
+ PRIORITY_ABOVE_NORMAL,
+ PRIORITY_HIGH,
+ PRIORITY_HIGHEST
+} = os.constants.priority;
+
+// Validate priority constants.
+assert.strictEqual(typeof PRIORITY_LOW, 'number');
+assert.strictEqual(typeof PRIORITY_BELOW_NORMAL, 'number');
+assert.strictEqual(typeof PRIORITY_NORMAL, 'number');
+assert.strictEqual(typeof PRIORITY_ABOVE_NORMAL, 'number');
+assert.strictEqual(typeof PRIORITY_HIGH, 'number');
+assert.strictEqual(typeof PRIORITY_HIGHEST, 'number');
+
+// Test pid type validation.
+[null, true, false, 'foo', {}, [], /x/].forEach((pid) => {
+ const errObj = {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "pid" argument must be of type number\./
+ };
+
+ common.expectsError(() => {
+ os.setPriority(pid, PRIORITY_NORMAL);
+ }, errObj);
+
+ common.expectsError(() => {
+ os.getPriority(pid);
+ }, errObj);
+});
+
+// Test pid range validation.
+[NaN, Infinity, -Infinity, 3.14, 2 ** 32].forEach((pid) => {
+ const errObj = {
+ code: 'ERR_OUT_OF_RANGE',
+ message: /The value of "pid" is out of range\./
+ };
+
+ common.expectsError(() => {
+ os.setPriority(pid, PRIORITY_NORMAL);
+ }, errObj);
+
+ common.expectsError(() => {
+ os.getPriority(pid);
+ }, errObj);
+});
+
+// Test priority type validation.
+[null, true, false, 'foo', {}, [], /x/].forEach((priority) => {
+ common.expectsError(() => {
+ os.setPriority(0, priority);
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /The "priority" argument must be of type number\./
+ });
+});
+
+// Test priority range validation.
+[
+ NaN,
+ Infinity,
+ -Infinity,
+ 3.14,
+ 2 ** 32,
+ PRIORITY_HIGHEST - 1,
+ PRIORITY_LOW + 1
+].forEach((priority) => {
+ common.expectsError(() => {
+ os.setPriority(0, priority);
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ message: /The value of "priority" is out of range\./
+ });
+});
+
+// Verify that valid values work.
+for (let i = PRIORITY_HIGHEST; i <= PRIORITY_LOW; i++) {
+ // A pid of 0 corresponds to the current process.
+ try {
+ os.setPriority(0, i);
+ } catch (err) {
+ // The current user might not have sufficient permissions to set this
+ // specific priority level. Skip this priority, but keep trying lower
+ // priorities.
+ if (err.info.code === 'EACCES')
+ continue;
+
+ assert(err);
+ }
+
+ checkPriority(0, i);
+
+ // An undefined pid corresponds to the current process.
+ os.setPriority(i);
+ checkPriority(undefined, i);
+
+ // Specifying the actual pid works.
+ os.setPriority(process.pid, i);
+ checkPriority(process.pid, i);
+}
+
+
+function checkPriority(pid, expected) {
+ const priority = os.getPriority(pid);
+
+ // Verify that the priority values match on Unix, and are range mapped on
+ // Windows.
+ if (!common.isWindows) {
+ assert.strictEqual(priority, expected);
+ return;
+ }
+
+ if (expected < PRIORITY_HIGH)
+ assert.strictEqual(priority, PRIORITY_HIGHEST);
+ else if (expected < PRIORITY_ABOVE_NORMAL)
+ assert.strictEqual(priority, PRIORITY_HIGH);
+ else if (expected < PRIORITY_NORMAL)
+ assert.strictEqual(priority, PRIORITY_ABOVE_NORMAL);
+ else if (expected < PRIORITY_BELOW_NORMAL)
+ assert.strictEqual(priority, PRIORITY_NORMAL);
+ else if (expected < PRIORITY_LOW)
+ assert.strictEqual(priority, PRIORITY_BELOW_NORMAL);
+ else
+ assert.strictEqual(priority, PRIORITY_LOW);
+}