Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

process: add nice() function #21675

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 34 additions & 0 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,40 @@ The next tick queue is completely drained on each pass of the event loop
`nextTick()` callbacks will block any I/O from happening, just like a
`while(true);` loop.

## process.nice([inc])
<!-- YAML
added: REPLACEME
-->

* `inc` {integer} The nice value which is added to the current nice value.
* Returns: {integer} The new nice value for the process.

The `process.nice()` method sets or gets the nice value of the process.
(See nice(2).) The `inc` is supposed to be an integer, consisting of the
_difference_ to be added to the current nice value of the process.
The higher the nice value of the process, the nicer the process and the less
time is given by the scheduler (effectively lowering the priority).

It is possible to get the current nice value by passing `0` or `undefined`
to the method.

In a common environment, it is only possible to increase the nice value.
A decrease of the value at a later time might not be possible (unless
the specified permissions are set). (See getrlimit(2).)

```js
if (process.platform !== 'win32') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think having this is necessary, especially since we already document Windows is not supported below this example.

const currentNice = process.nice();
console.log(currentNice); // Prints the current nice value.

process.nice(1); // Increases nice value - giving it less priority.
}
```

This function works only on POSIX platforms and throws not implemented errors
on other platforms.
This feature is not available in [`Worker`][] threads.

## process.noDeprecation
<!-- YAML
added: v0.8.0
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
_hrtime, _hrtimeBigInt,
_memoryUsage, _rawDebug,
_umask, _initgroups, _setegid, _seteuid,
_setgid, _setuid, _setgroups,
_nice, _setgid, _setuid, _setgroups,
_shouldAbortOnUncaughtToggle },
{ internalBinding, NativeModule }) {
const exceptionHandlerState = { captureFn: null };
Expand Down Expand Up @@ -77,7 +77,7 @@
if (isMainThread) {
mainThreadSetup.setupStdio();
mainThreadSetup.setupProcessMethods(
_chdir, _umask, _initgroups, _setegid, _seteuid,
_chdir, _umask, _initgroups, _setegid, _seteuid, _nice,
_setgid, _setuid, _setgroups
);
} else {
Expand Down
27 changes: 24 additions & 3 deletions lib/internal/process/main_thread_only.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ const {
errnoException,
codes: {
ERR_INVALID_ARG_TYPE,
ERR_UNKNOWN_CREDENTIAL
ERR_UNKNOWN_CREDENTIAL,
ERR_METHOD_NOT_IMPLEMENTED
}
} = require('internal/errors');
const {
validateMode,
validateUint32
validateUint32,
validateInt32
} = require('internal/validators');

const {
Expand All @@ -29,12 +31,23 @@ function setupStdio() {
// Non-POSIX platforms like Windows don't have certain methods.
// Workers also lack these methods since they change process-global state.
function setupProcessMethods(_chdir, _umask, _initgroups, _setegid,
_seteuid, _setgid, _setuid, _setgroups) {
_seteuid, _nice, _setgid, _setuid,
_setgroups) {

if (_setgid !== undefined) {
setupPosixMethods(_initgroups, _setegid, _seteuid,
_setgid, _setuid, _setgroups);
}

process.nice = function nice(inc) {
if (process.platform === 'win32') {
Copy link
Contributor

@mscdex mscdex Jul 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps change this so the platform check is only run once when this file is evaluated, since the process platform will not change during runtime. Example:

if (process.platform === 'win32') {
  process.nice = function nice(inc) {
    throw new ERR_METHOD_NOT_IMPLEMENTED('nice()');
  };
} else {
  process.nice = function nice(inc) {
    validateInc(inc);
    return _nice(inc);
  };
}

or something similar

throw new ERR_METHOD_NOT_IMPLEMENTED('nice()');
}

validateInc(inc);
return _nice(inc);
};

process.chdir = function chdir(directory) {
if (typeof directory !== 'string') {
throw new ERR_INVALID_ARG_TYPE('directory', 'string', directory);
Expand All @@ -50,6 +63,14 @@ function setupProcessMethods(_chdir, _umask, _initgroups, _setegid,
mask = validateMode(mask, 'mask');
return _umask(mask);
};

function validateInc(inc) {
if (typeof inc === 'number') {
validateInt32(inc, 'nice');
} else if (inc !== undefined) {
throw new ERR_INVALID_ARG_TYPE('nice', ['number', 'undefined'], inc);
}
}
}

function setupPosixMethods(_initgroups, _setegid, _seteuid,
Expand Down
1 change: 1 addition & 0 deletions src/bootstrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ void SetupBootstrapObject(Environment* env,
BOOTSTRAP_METHOD(_initgroups, InitGroups);
BOOTSTRAP_METHOD(_setegid, SetEGid);
BOOTSTRAP_METHOD(_seteuid, SetEUid);
BOOTSTRAP_METHOD(_nice, Nice);
BOOTSTRAP_METHOD(_setgid, SetGid);
BOOTSTRAP_METHOD(_setuid, SetUid);
BOOTSTRAP_METHOD(_setgroups, SetGroups);
Expand Down
2 changes: 1 addition & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ typedef int mode_t;
#else
#include <pthread.h>
#include <sys/resource.h> // getrlimit, setrlimit
#include <unistd.h> // setuid, getuid
#include <unistd.h> // setuid, getuid, nice
#endif

#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__)
Expand Down
4 changes: 4 additions & 0 deletions src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,10 @@ void StopProfilerIdleNotifier(const v8::FunctionCallbackInfo<v8::Value>& args);
void Umask(const v8::FunctionCallbackInfo<v8::Value>& args);
void Uptime(const v8::FunctionCallbackInfo<v8::Value>& args);

#if defined(__POSIX__) && !defined(__CloudABI__)
void Nice(const v8::FunctionCallbackInfo<v8::Value>& args);
#endif // __POSIX__ && !defined(__CloudABI__)

#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__)
void SetGid(const v8::FunctionCallbackInfo<v8::Value>& args);
void SetEGid(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down
25 changes: 25 additions & 0 deletions src/node_process.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ using v8::BigUint64Array;
using v8::Float64Array;
using v8::FunctionCallbackInfo;
using v8::HeapStatistics;
using v8::Int32;
using v8::Integer;
using v8::Isolate;
using v8::Local;
Expand Down Expand Up @@ -434,6 +435,30 @@ void SetEUid(const FunctionCallbackInfo<Value>& args) {
}


void Nice(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->is_main_thread());

CHECK_EQ(args.Length(), 1);

int inc = 0;
// ..only check type if argument is int32
if (!args[0]->IsUndefined()) {
CHECK(args[0]->IsInt32());
inc = args[0].As<Int32>()->Value();
}

errno = 0;
int nice_result = nice(inc);

if (errno != 0) {
env->ThrowErrnoException(errno, "nice");
} else {
args.GetReturnValue().Set(nice_result);
}
}


void GetGroups(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Expand Down
47 changes: 47 additions & 0 deletions test/parallel/test-process-nice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';
const common = require('../common');
const assert = require('assert');

if (common.isWindows || !common.isMainThread) {
assert.strictEqual(process.nice, undefined);
Copy link
Contributor

@mscdex mscdex Jul 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer valid since we're now throwing.

However, I feel like we should just call common.skip() with an appropriate message to make it obvious that we're not testing the real implementation.

return;
}

assert.throws(
() => {
process.nice(NaN);
},
{
code: 'ERR_OUT_OF_RANGE',
name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "nice" is out of range. It must be ' +
'an integer. Received NaN'
}
);

assert.throws(
() => {
process.nice(Infinity);
},
{
code: 'ERR_OUT_OF_RANGE',
name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "nice" is out of range. It must be ' +
'an integer. Received Infinity'
}
);

[null, false, true, {}, [], () => {}, 'text'].forEach((val) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about also testing that passing '0' or undefined results in a finite integer being returned?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we might want to test that something like process.nice(1) works as expected.

assert.throws(
() => {
process.nice(val);
},
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: 'The "nice" argument must be ' +
'one of type number or undefined. ' +
`Received type ${typeof val}`
}
);
});