@@ -19,8 +19,13 @@ pub const ref = RefCount.ref;
1919pub const deref = RefCount .deref ;
2020
2121ref_count : RefCount ,
22- writer : WriterImpl = if (bun .Environment .isWindows ) .{} else .{ .close_fd = false },
23- fd : bun.FileDescriptor ,
22+ writer : WriterImpl = if (bun .Environment .isWindows ) .{
23+ // Tell the Windows PipeWriter impl to *not* close the file descriptor,
24+ // unfortunately this won't work if it creates a uv_pipe or uv_tty as those
25+ // types own their file descriptor
26+ .owns_fd = false ,
27+ } else .{ .close_fd = false },
28+ fd : MovableIfWindowsFd ,
2429writers : Writers = .{ .inlined = .{} },
2530buf : std .ArrayListUnmanaged (u8 ) = .{},
2631/// quick hack to get windows working
@@ -81,7 +86,7 @@ pub const Flags = packed struct(u8) {
8186pub fn init (fd : bun.FileDescriptor , flags : Flags , evtloop : jsc.EventLoopHandle ) * IOWriter {
8287 const this = bun .new (IOWriter , .{
8388 .ref_count = .init (),
84- .fd = fd ,
89+ .fd = MovableIfWindowsFd . init ( fd ) ,
8590 .evtloop = evtloop ,
8691 .concurrent_task = jsc .EventLoopTask .fromEventLoop (evtloop ),
8792 .concurrent_task2 = jsc .EventLoopTask .fromEventLoop (evtloop ),
@@ -96,8 +101,9 @@ pub fn init(fd: bun.FileDescriptor, flags: Flags, evtloop: jsc.EventLoopHandle)
96101}
97102
98103pub fn __start (this : * IOWriter ) Maybe (void ) {
104+ bun .assert (this .fd .isOwned ());
99105 debug ("IOWriter(0x{x}, fd={}) __start()" , .{ @intFromPtr (this ), this .fd });
100- if (this .writer .start (this .fd , this .flags .pollable ).asErr ()) | e_ | {
106+ if (this .writer .start (& this .fd , this .flags .pollable ).asErr ()) | e_ | {
101107 const e : bun.sys.Error = e_ ;
102108 if (bun .Environment .isPosix ) {
103109 // We get this if we pass in a file descriptor that is not
@@ -140,7 +146,7 @@ pub fn __start(this: *IOWriter) Maybe(void) {
140146 this .flags .pollable = false ;
141147 this .flags .nonblocking = false ;
142148 this .flags .is_socket = false ;
143- return this .writer .startWithFile (this .fd );
149+ return this .writer .startWithFile (this .fd . get () .? );
144150 }
145151 }
146152 return .{ .err = e };
@@ -157,6 +163,10 @@ pub fn __start(this: *IOWriter) Maybe(void) {
157163 }
158164 }
159165
166+ if (comptime bun .Environment .isWindows ) {
167+ log ("IOWriter(0x{x}, {}) starting with source={s}" , .{ @intFromPtr (this ), this .fd , if (this .writer .source ) | src | @tagName (src ) else "no source lol" });
168+ }
169+
160170 return .success ;
161171}
162172
@@ -637,6 +647,7 @@ pub fn enqueueFmt(
637647
638648fn asyncDeinit (this : * @This ()) void {
639649 debug ("IOWriter(0x{x}, fd={}) asyncDeinit" , .{ @intFromPtr (this ), this .fd });
650+ bun .assert (! this .is_writing );
640651 this .async_deinit .enqueue ();
641652}
642653
@@ -648,7 +659,10 @@ pub fn deinitOnMainThread(this: *IOWriter) void {
648659 if (this .writer .handle == .poll and this .writer .handle .poll .isRegistered ()) {
649660 this .writer .handle .closeImpl (null , {}, false );
650661 }
651- } else this .winbuf .deinit (bun .default_allocator );
662+ } else {
663+ this .writer .close ();
664+ this .winbuf .deinit (bun .default_allocator );
665+ }
652666 if (this .fd .isValid ()) this .fd .close ();
653667 this .writer .disableKeepingProcessAlive (this .evtloop );
654668 bun .destroy (this );
@@ -760,14 +774,15 @@ fn tryWriteWithWriteFn(fd: bun.FileDescriptor, buf: []const u8, comptime write_f
760774}
761775
762776pub fn drainBufferedData (parent : * IOWriter , buf : []const u8 , max_write_size : usize , received_hup : bool ) bun.io.WriteResult {
777+ bun .assert (bun .Environment .isPosix );
763778 _ = received_hup ;
764779
765780 const trimmed = if (max_write_size < buf .len and max_write_size > 0 ) buf [0.. max_write_size ] else buf ;
766781
767782 var drained : usize = 0 ;
768783
769784 while (drained < trimmed .len ) {
770- const attempt = tryWriteWithWriteFn (parent .fd , buf , bun .sys .write );
785+ const attempt = tryWriteWithWriteFn (parent .fd . get () .? , buf , bun .sys .write );
771786 switch (attempt ) {
772787 .pending = > | pending | {
773788 drained += pending ;
@@ -840,6 +855,7 @@ const log = bun.Output.scoped(.IOWriter, .hidden);
840855const std = @import ("std" );
841856
842857const bun = @import ("bun" );
858+ const MovableIfWindowsFd = bun .MovableIfWindowsFd ;
843859const assert = bun .assert ;
844860const jsc = bun .jsc ;
845861const Maybe = bun .sys .Maybe ;
0 commit comments