@@ -60,6 +60,7 @@ namespace fs {
60
60
61
61
using v8::Array;
62
62
using v8::BigInt;
63
+ using v8::CFunction;
63
64
using v8::Context;
64
65
using v8::EscapableHandleScope;
65
66
using v8::FastApiCallbackOptions;
@@ -966,32 +967,67 @@ void Access(const FunctionCallbackInfo<Value>& args) {
966
967
}
967
968
}
968
969
969
- void Close (const FunctionCallbackInfo<Value>& args) {
970
+ static void Close (const FunctionCallbackInfo<Value>& args) {
970
971
Environment* env = Environment::GetCurrent (args);
971
972
972
- const int argc = args.Length ();
973
- CHECK_GE (argc, 1 );
973
+ CHECK_EQ (args.Length (), 2 ); // fd, req
974
974
975
975
int fd;
976
976
if (!GetValidatedFd (env, args[0 ]).To (&fd)) {
977
977
return ;
978
978
}
979
979
env->RemoveUnmanagedFd (fd);
980
980
981
- if (argc > 1 ) { // close(fd, req)
982
- FSReqBase* req_wrap_async = GetReqWrap (args, 1 );
983
- CHECK_NOT_NULL (req_wrap_async);
984
- FS_ASYNC_TRACE_BEGIN0 (UV_FS_CLOSE, req_wrap_async)
985
- AsyncCall (env, req_wrap_async, args, " close" , UTF8, AfterNoArgs,
986
- uv_fs_close, fd);
987
- } else { // close(fd)
988
- FSReqWrapSync req_wrap_sync (" close" );
989
- FS_SYNC_TRACE_BEGIN (close );
990
- SyncCallAndThrowOnError (env, &req_wrap_sync, uv_fs_close, fd);
991
- FS_SYNC_TRACE_END (close );
981
+ FSReqBase* req_wrap_async = GetReqWrap (args, 1 );
982
+ CHECK_NOT_NULL (req_wrap_async);
983
+ FS_ASYNC_TRACE_BEGIN0 (UV_FS_CLOSE, req_wrap_async)
984
+ AsyncCall (
985
+ env, req_wrap_async, args, " close" , UTF8, AfterNoArgs, uv_fs_close, fd);
986
+ }
987
+
988
+ // Separate implementations are required to provide fast API for closeSync.
989
+ // If both close and closeSync are implemented using the same function, and
990
+ // if a fast API implementation is added for closeSync, close(fd, req) will
991
+ // also trigger the fast API implementation and cause an incident.
992
+ // Ref: https://github.com/nodejs/node/issues/53902
993
+ static void CloseSync (const FunctionCallbackInfo<Value>& args) {
994
+ Environment* env = Environment::GetCurrent (args);
995
+ CHECK_EQ (args.Length (), 1 );
996
+
997
+ int fd;
998
+ if (!GetValidatedFd (env, args[0 ]).To (&fd)) {
999
+ return ;
1000
+ }
1001
+ env->RemoveUnmanagedFd (fd);
1002
+ FSReqWrapSync req_wrap_sync (" close" );
1003
+ FS_SYNC_TRACE_BEGIN (close );
1004
+ SyncCallAndThrowOnError (env, &req_wrap_sync, uv_fs_close, fd);
1005
+ FS_SYNC_TRACE_END (close );
1006
+ }
1007
+
1008
+ static void FastCloseSync (Local<Object> recv,
1009
+ const uint32_t fd,
1010
+ // NOLINTNEXTLINE(runtime/references) This is V8 api.
1011
+ v8::FastApiCallbackOptions& options) {
1012
+ Environment* env = Environment::GetCurrent (recv->GetCreationContextChecked ());
1013
+
1014
+ uv_fs_t req;
1015
+ FS_SYNC_TRACE_BEGIN (close );
1016
+ int err = uv_fs_close (nullptr , &req, fd, nullptr );
1017
+ FS_SYNC_TRACE_END (close );
1018
+
1019
+ if (is_uv_error (err)) {
1020
+ options.fallback = true ;
1021
+ } else {
1022
+ // Note: Only remove unmanaged fds if the close was successful.
1023
+ // RemoveUnmanagedFd() can call ProcessEmitWarning() which calls back into
1024
+ // JS process.emitWarning() and violates the fast API protocol.
1025
+ env->RemoveUnmanagedFd (fd, Environment::kSetImmediate );
992
1026
}
993
1027
}
994
1028
1029
+ CFunction fast_close_sync_ (CFunction::Make(FastCloseSync));
1030
+
995
1031
static void ExistsSync (const FunctionCallbackInfo<Value>& args) {
996
1032
Environment* env = Environment::GetCurrent (args);
997
1033
Isolate* isolate = env->isolate ();
@@ -3408,6 +3444,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
3408
3444
GetFormatOfExtensionlessFile);
3409
3445
SetMethod (isolate, target, " access" , Access);
3410
3446
SetMethod (isolate, target, " close" , Close);
3447
+ SetFastMethod (isolate, target, " closeSync" , CloseSync, &fast_close_sync_);
3411
3448
SetMethod (isolate, target, " existsSync" , ExistsSync);
3412
3449
SetMethod (isolate, target, " open" , Open);
3413
3450
SetMethod (isolate, target, " openFileHandle" , OpenFileHandle);
@@ -3533,6 +3570,9 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
3533
3570
3534
3571
registry->Register (GetFormatOfExtensionlessFile);
3535
3572
registry->Register (Close);
3573
+ registry->Register (CloseSync);
3574
+ registry->Register (FastCloseSync);
3575
+ registry->Register (fast_close_sync_.GetTypeInfo ());
3536
3576
registry->Register (ExistsSync);
3537
3577
registry->Register (Open);
3538
3578
registry->Register (OpenFileHandle);
0 commit comments