Skip to content

Commit 20e08f9

Browse files
shiavm006kgryte
andauthored
fix: prevent deadlock on single-core systems and with empty arrays in utils/parallel
PR-URL: #9597 Co-authored-by: Athan Reines <[email protected]> Reviewed-by: Athan Reines <[email protected]>
1 parent 4669c51 commit 20e08f9

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed

lib/node_modules/@stdlib/utils/parallel/lib/defaults.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
// MODULES //
2222

2323
var numCPUs = require( '@stdlib/os/num-cpus' );
24+
var max = require( '@stdlib/math/base/special/fast/max' );
2425

2526

2627
// MAIN //
@@ -36,12 +37,17 @@ var numCPUs = require( '@stdlib/os/num-cpus' );
3637
* // returns {...}
3738
*/
3839
function defaults() {
40+
var n;
41+
42+
// Accommodate single-core systems by ensuring at least 1 worker and 1 concurrent script:
43+
n = max( 1, numCPUs - 1 );
44+
3945
return {
4046
// Number of workers:
41-
'workers': numCPUs - 1,
47+
'workers': n,
4248

4349
// Number of scripts to execute concurrently:
44-
'concurrency': numCPUs - 1,
50+
'concurrency': n,
4551

4652
// Executable file/command:
4753
'cmd': 'node',

lib/node_modules/@stdlib/utils/parallel/lib/main.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ function parallel() {
9494
if ( !isFunction( clbk ) ) {
9595
throw new TypeError( format( 'invalid argument. Callback argument must be a function. Value: `%s`.', clbk ) );
9696
}
97-
// Prevent the number of concurrent scripts exceeding the number of actual scripts to run.
97+
// Prevent the number of concurrent scripts exceeding the number of actual scripts to run:
9898
if ( opts.concurrency > files.length ) {
99-
opts.concurrency = files.length;
99+
opts.concurrency = files.length || 1;
100100
}
101-
// Prevent the number of workers exceeding the number of concurrent scripts (excess capacity), as some workers would never be allocated scripts to run and always be idle.
101+
// Prevent the number of workers exceeding the number of concurrent scripts (excess capacity), as some workers would never be allocated scripts to run and always be idle:
102102
if ( opts.workers > opts.concurrency ) {
103103
opts.workers = opts.concurrency;
104104
}

lib/node_modules/@stdlib/utils/parallel/test/test.main.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,45 @@ tape( 'if the number of workers is greater than the concurrency, the function se
305305
}
306306
});
307307

308+
tape( 'the function ensures at least one worker and a concurrency greater than or equal to unity', function test( t ) {
309+
var parallel;
310+
311+
parallel = proxyquire( './../lib/main.js', {
312+
'./node': exec,
313+
'./defaults.js': mockDefaults
314+
});
315+
316+
parallel( files(), done );
317+
318+
function mockDefaults() {
319+
return {
320+
'workers': 1,
321+
'concurrency': 1,
322+
'cmd': 'node',
323+
'ordered': false,
324+
'uid': null,
325+
'gid': null,
326+
'encoding': 'buffer',
327+
'maxBuffer': 200 * 1024 * 1024
328+
};
329+
}
330+
331+
function done( error ) {
332+
if ( error ) {
333+
t.ok( false, error.message );
334+
} else {
335+
t.ok( true, 'runs scripts successfully' );
336+
}
337+
t.end();
338+
}
339+
340+
function exec( files, opts, clbk ) {
341+
t.strictEqual( opts.workers, 1, 'has at least 1 worker' );
342+
t.strictEqual( opts.concurrency, 1, 'has at least 1 concurrency' );
343+
clbk();
344+
}
345+
});
346+
308347
tape( 'the function runs scripts in parallel', function test( t ) {
309348
parallel( files(), done );
310349
function done( error ) {

0 commit comments

Comments
 (0)