-
Notifications
You must be signed in to change notification settings - Fork 224
/
fibers.js
132 lines (114 loc) · 3.69 KB
/
fibers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
if (process.fiberLib) {
module.exports = process.fiberLib;
} else {
var fs = require('fs'), path = require('path'), detectLibc = require('detect-libc');
// Seed random numbers [gh-82]
Math.random();
// Look for binary for this platform
var modPath = path.join(__dirname, 'bin', process.platform+ '-'+ process.arch+ '-'+ process.versions.modules+
((process.platform === 'linux') ? '-'+ detectLibc.family : ''), 'fibers');
try {
// Pull in fibers implementation
process.fiberLib = module.exports = require(modPath).Fiber;
} catch (ex) {
// No binary!
console.error(
'## There is an issue with `node-fibers` ##\n'+
'`'+ modPath+ '.node` is missing.\n\n'+
'Try running this to fix the issue: '+ process.execPath+ ' '+ __dirname.replace(' ', '\\ ')+ '/build'
);
console.error(ex.stack || ex.message || ex);
throw new Error('Missing binary. See message above.');
}
setupAsyncHacks(module.exports);
}
function setupAsyncHacks(Fiber) {
// Older (or newer?) versions of node may not support this API
try {
var aw = process.binding('async_wrap');
var getAsyncIdStackSize;
if (aw.asyncIdStackSize instanceof Function) {
getAsyncIdStackSize = aw.asyncIdStackSize;
} else if (aw.constants.kStackLength !== undefined) {
getAsyncIdStackSize = function(kStackLength) {
return function() {
return aw.async_hook_fields[kStackLength];
};
}(aw.constants.kStackLength);
} else {
throw new Error('Couldn\'t figure out how to get async stack size');
}
var popAsyncContext = aw.popAsyncContext || aw.popAsyncIds;
var pushAsyncContext = aw.pushAsyncContext || aw.pushAsyncIds;
if (!popAsyncContext || !pushAsyncContext) {
throw new Error('Push/pop do not exist');
}
var kExecutionAsyncId;
if (aw.constants.kExecutionAsyncId === undefined) {
kExecutionAsyncId = aw.constants.kCurrentAsyncId;
} else {
kExecutionAsyncId = aw.constants.kExecutionAsyncId;
}
var kTriggerAsyncId;
if (aw.constants.kTriggerAsyncId === undefined) {
kTriggerAsyncId = aw.constants.kCurrentTriggerId;
} else {
kTriggerAsyncId = aw.constants.kTriggerAsyncId;
}
var asyncIds = aw.async_id_fields || aw.async_uid_fields;
function getAndClearStack() {
var ii = getAsyncIdStackSize();
var stack = new Array(ii);
for (; ii > 0; --ii) {
var asyncId = asyncIds[kExecutionAsyncId];
stack[ii - 1] = {
asyncId: asyncId,
triggerId: asyncIds[kTriggerAsyncId],
};
popAsyncContext(asyncId);
}
return stack;
}
function restoreStack(stack) {
for (var ii = 0; ii < stack.length; ++ii) {
pushAsyncContext(stack[ii].asyncId, stack[ii].triggerId);
}
}
function logUsingFibers(fibersMethod) {
const logUseFibersLevel = +(process.env.ENABLE_LOG_USE_FIBERS || 0);
if (!logUseFibersLevel) return;
if (logUseFibersLevel === 1) {
console.warn(`[FIBERS_LOG] Using ${fibersMethod}.`);
return;
}
const { LOG_USE_FIBERS_INCLUDE_IN_PATH } = process.env;
const stackFromError = new Error(`[FIBERS_LOG] Using ${fibersMethod}.`).stack;
if (
!LOG_USE_FIBERS_INCLUDE_IN_PATH ||
stackFromError.includes(LOG_USE_FIBERS_INCLUDE_IN_PATH)
) {
console.warn(stackFromError);
}
}
function wrapFunction(fn, fibersMethod) {
return function () {
logUsingFibers(fibersMethod);
var stack = getAndClearStack();
try {
return fn.apply(this, arguments);
} finally {
restoreStack(stack);
}
};
}
// Monkey patch methods which may long jump
Fiber.yield = wrapFunction(Fiber.yield, "Fiber.yield");
Fiber.prototype.run = wrapFunction(Fiber.prototype.run, "Fiber.run");
Fiber.prototype.throwInto = wrapFunction(
Fiber.prototype.throwInto,
"Fiber.throwInto"
);
} catch (err) {
return;
}
}