@@ -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;
@@ -971,32 +972,67 @@ void Access(const FunctionCallbackInfo<Value>& args) {
971
972
}
972
973
}
973
974
974
- void Close (const FunctionCallbackInfo<Value>& args) {
975
+ static void Close (const FunctionCallbackInfo<Value>& args) {
975
976
Environment* env = Environment::GetCurrent (args);
976
977
977
- const int argc = args.Length ();
978
- CHECK_GE (argc, 1 );
978
+ CHECK_EQ (args.Length (), 2 ); // fd, req
979
979
980
980
int fd;
981
981
if (!GetValidatedFd (env, args[0 ]).To (&fd)) {
982
982
return ;
983
983
}
984
984
env->RemoveUnmanagedFd (fd);
985
985
986
- if (argc > 1 ) { // close(fd, req)
987
- FSReqBase* req_wrap_async = GetReqWrap (args, 1 );
988
- CHECK_NOT_NULL (req_wrap_async);
989
- FS_ASYNC_TRACE_BEGIN0 (UV_FS_CLOSE, req_wrap_async)
990
- AsyncCall (env, req_wrap_async, args, " close" , UTF8, AfterNoArgs,
991
- uv_fs_close, fd);
992
- } else { // close(fd)
993
- FSReqWrapSync req_wrap_sync (" close" );
994
- FS_SYNC_TRACE_BEGIN (close);
995
- SyncCallAndThrowOnError (env, &req_wrap_sync, uv_fs_close, fd);
996
- FS_SYNC_TRACE_END (close);
986
+ FSReqBase* req_wrap_async = GetReqWrap (args, 1 );
987
+ CHECK_NOT_NULL (req_wrap_async);
988
+ FS_ASYNC_TRACE_BEGIN0 (UV_FS_CLOSE, req_wrap_async)
989
+ AsyncCall (
990
+ env, req_wrap_async, args, " close" , UTF8, AfterNoArgs, uv_fs_close, fd);
991
+ }
992
+
993
+ // Separate implementations are required to provide fast API for closeSync.
994
+ // If both close and closeSync are implemented using the same function, and
995
+ // if a fast API implementation is added for closeSync, close(fd, req) will
996
+ // also trigger the fast API implementation and cause an incident.
997
+ // Ref: https://github.com/nodejs/node/issues/53902
998
+ static void CloseSync (const FunctionCallbackInfo<Value>& args) {
999
+ Environment* env = Environment::GetCurrent (args);
1000
+ CHECK_EQ (args.Length (), 1 );
1001
+
1002
+ int fd;
1003
+ if (!GetValidatedFd (env, args[0 ]).To (&fd)) {
1004
+ return ;
1005
+ }
1006
+ env->RemoveUnmanagedFd (fd);
1007
+ FSReqWrapSync req_wrap_sync (" close" );
1008
+ FS_SYNC_TRACE_BEGIN (close);
1009
+ SyncCallAndThrowOnError (env, &req_wrap_sync, uv_fs_close, fd);
1010
+ FS_SYNC_TRACE_END (close);
1011
+ }
1012
+
1013
+ static void FastCloseSync (Local<Object> recv,
1014
+ const uint32_t fd,
1015
+ // NOLINTNEXTLINE(runtime/references) This is V8 api.
1016
+ v8::FastApiCallbackOptions& options) {
1017
+ Environment* env = Environment::GetCurrent (recv->GetCreationContextChecked ());
1018
+
1019
+ uv_fs_t req;
1020
+ FS_SYNC_TRACE_BEGIN (close);
1021
+ int err = uv_fs_close (nullptr , &req, fd, nullptr );
1022
+ FS_SYNC_TRACE_END (close);
1023
+
1024
+ if (is_uv_error (err)) {
1025
+ options.fallback = true ;
1026
+ } else {
1027
+ // Note: Only remove unmanaged fds if the close was successful.
1028
+ // RemoveUnmanagedFd() can call ProcessEmitWarning() which calls back into
1029
+ // JS process.emitWarning() and violates the fast API protocol.
1030
+ env->RemoveUnmanagedFd (fd, Environment::kSetImmediate );
997
1031
}
998
1032
}
999
1033
1034
+ CFunction fast_close_sync_ (CFunction::Make(FastCloseSync));
1035
+
1000
1036
static void ExistsSync (const FunctionCallbackInfo<Value>& args) {
1001
1037
Environment* env = Environment::GetCurrent (args);
1002
1038
Isolate* isolate = env->isolate ();
@@ -3547,6 +3583,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
3547
3583
GetFormatOfExtensionlessFile);
3548
3584
SetMethod (isolate, target, " access" , Access);
3549
3585
SetMethod (isolate, target, " close" , Close);
3586
+ SetFastMethod (isolate, target, " closeSync" , CloseSync, &fast_close_sync_);
3550
3587
SetMethod (isolate, target, " existsSync" , ExistsSync);
3551
3588
SetMethod (isolate, target, " open" , Open);
3552
3589
SetMethod (isolate, target, " openFileHandle" , OpenFileHandle);
@@ -3674,6 +3711,9 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
3674
3711
3675
3712
registry->Register (GetFormatOfExtensionlessFile);
3676
3713
registry->Register (Close);
3714
+ registry->Register (CloseSync);
3715
+ registry->Register (FastCloseSync);
3716
+ registry->Register (fast_close_sync_.GetTypeInfo ());
3677
3717
registry->Register (ExistsSync);
3678
3718
registry->Register (Open);
3679
3719
registry->Register (OpenFileHandle);
0 commit comments