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

lib: refactor Timeout, ImmediateList, TimersList to class #37408

Merged
merged 1 commit into from
Apr 4, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 120 additions & 115 deletions lib/internal/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,6 @@ let timerListId = NumberMIN_SAFE_INTEGER;

const kRefed = Symbol('refed');

// Create a single linked list instance only once at startup
const immediateQueue = new ImmediateList();

let nextExpiry = Infinity;
let refCount = 0;

Expand All @@ -161,140 +158,148 @@ function initAsyncResource(resource, type) {
if (initHooksExist())
emitInit(asyncId, type, triggerAsyncId, resource);
}

// Timer constructor function.
// The entire prototype is defined in lib/timers.js
function Timeout(callback, after, args, isRepeat, isRefed) {
after *= 1; // Coalesce to number or NaN
if (!(after >= 1 && after <= TIMEOUT_MAX)) {
if (after > TIMEOUT_MAX) {
process.emitWarning(`${after} does not fit into` +
' a 32-bit signed integer.' +
'\nTimeout duration was set to 1.',
'TimeoutOverflowWarning');
class Timeout {
// Timer constructor function.
// The entire prototype is defined in lib/timers.js
constructor(callback, after, args, isRepeat, isRefed) {
after *= 1; // Coalesce to number or NaN
if (!(after >= 1 && after <= TIMEOUT_MAX)) {
if (after > TIMEOUT_MAX) {
process.emitWarning(`${after} does not fit into` +
' a 32-bit signed integer.' +
'\nTimeout duration was set to 1.',
'TimeoutOverflowWarning');
}
after = 1; // Schedule on next tick, follows browser behavior
}
after = 1; // Schedule on next tick, follows browser behavior
}

this._idleTimeout = after;
this._idlePrev = this;
this._idleNext = this;
this._idleStart = null;
// This must be set to null first to avoid function tracking
// on the hidden class, revisit in V8 versions after 6.2
this._onTimeout = null;
this._onTimeout = callback;
this._timerArgs = args;
this._repeat = isRepeat ? after : null;
this._destroyed = false;

if (isRefed)
incRefCount();
this[kRefed] = isRefed;
this[kHasPrimitive] = false;

initAsyncResource(this, 'Timeout');
}
this._idleTimeout = after;
this._idlePrev = this;
this._idleNext = this;
this._idleStart = null;
// This must be set to null first to avoid function tracking
// on the hidden class, revisit in V8 versions after 6.2
this._onTimeout = null;
this._onTimeout = callback;
this._timerArgs = args;
this._repeat = isRepeat ? after : null;
this._destroyed = false;

// Make sure the linked list only shows the minimal necessary information.
Timeout.prototype[inspect.custom] = function(_, options) {
return inspect(this, {
...options,
// Only inspect one level.
depth: 0,
// It should not recurse.
customInspect: false
});
};
if (isRefed)
incRefCount();
this[kRefed] = isRefed;
this[kHasPrimitive] = false;

Timeout.prototype.refresh = function() {
if (this[kRefed])
active(this);
else
unrefActive(this);
initAsyncResource(this, 'Timeout');
}

return this;
};
// Make sure the linked list only shows the minimal necessary information.
[inspect.custom](_, options) {
return inspect(this, {
...options,
// Only inspect one level.
depth: 0,
// It should not recurse.
customInspect: false
});
}

Timeout.prototype.unref = function() {
if (this[kRefed]) {
this[kRefed] = false;
if (!this._destroyed)
decRefCount();
refresh() {
if (this[kRefed])
active(this);
else
unrefActive(this);

return this;
}
return this;
};

Timeout.prototype.ref = function() {
if (!this[kRefed]) {
this[kRefed] = true;
if (!this._destroyed)
incRefCount();
unref() {
if (this[kRefed]) {
this[kRefed] = false;
if (!this._destroyed)
decRefCount();
}
return this;
}
return this;
};

Timeout.prototype.hasRef = function() {
return this[kRefed];
};
ref() {
if (!this[kRefed]) {
this[kRefed] = true;
if (!this._destroyed)
incRefCount();
}
return this;
}

function TimersList(expiry, msecs) {
this._idleNext = this; // Create the list with the linkedlist properties to
this._idlePrev = this; // Prevent any unnecessary hidden class changes.
this.expiry = expiry;
this.id = timerListId++;
this.msecs = msecs;
this.priorityQueuePosition = null;
hasRef() {
return this[kRefed];
}
}

// Make sure the linked list only shows the minimal necessary information.
TimersList.prototype[inspect.custom] = function(_, options) {
return inspect(this, {
...options,
// Only inspect one level.
depth: 0,
// It should not recurse.
customInspect: false
});
};
class TimersList {
constructor(expiry, msecs) {
this._idleNext = this; // Create the list with the linkedlist properties to
this._idlePrev = this; // Prevent any unnecessary hidden class changes.
this.expiry = expiry;
this.id = timerListId++;
this.msecs = msecs;
this.priorityQueuePosition = null;
}

// A linked list for storing `setImmediate()` requests
function ImmediateList() {
this.head = null;
this.tail = null;
// Make sure the linked list only shows the minimal necessary information.
[inspect.custom](_, options) {
return inspect(this, {
...options,
// Only inspect one level.
depth: 0,
// It should not recurse.
customInspect: false
});
}
}

// Appends an item to the end of the linked list, adjusting the current tail's
// next pointer and the item's previous pointer where applicable
ImmediateList.prototype.append = function(item) {
if (this.tail !== null) {
this.tail._idleNext = item;
item._idlePrev = this.tail;
} else {
this.head = item;
// A linked list for storing `setImmediate()` requests
class ImmediateList {
constructor() {
this.head = null;
this.tail = null;
}
this.tail = item;
};

// Removes an item from the linked list, adjusting the pointers of adjacent
// items and the linked list's head or tail pointers as necessary
ImmediateList.prototype.remove = function(item) {
if (item._idleNext) {
item._idleNext._idlePrev = item._idlePrev;
// Appends an item to the end of the linked list, adjusting the current tail's
// next pointer and the item's previous pointer where applicable
append(item) {
if (this.tail !== null) {
this.tail._idleNext = item;
item._idlePrev = this.tail;
} else {
this.head = item;
}
this.tail = item;
}

if (item._idlePrev) {
item._idlePrev._idleNext = item._idleNext;
}
// Removes an item from the linked list, adjusting the pointers of adjacent
// items and the linked list's head or tail pointers as necessary
remove(item) {
if (item._idleNext) {
item._idleNext._idlePrev = item._idlePrev;
}

if (item === this.head)
this.head = item._idleNext;
if (item === this.tail)
this.tail = item._idlePrev;
if (item._idlePrev) {
item._idlePrev._idleNext = item._idleNext;
}

item._idleNext = null;
item._idlePrev = null;
};
if (item === this.head)
this.head = item._idleNext;
if (item === this.tail)
this.tail = item._idlePrev;

item._idleNext = null;
item._idlePrev = null;
}
}

// Create a single linked list instance only once at startup
const immediateQueue = new ImmediateList();

function incRefCount() {
if (refCount++ === 0)
Expand Down