@@ -3,6 +3,7 @@ require "termios"
33{% if flag?(:android ) && LibC ::ANDROID_API < 28 % }
44 require " c/sys/ioctl"
55{% end % }
6+ require " crystal/fd_lock"
67
78# :nodoc:
89module Crystal::System::FileDescriptor
@@ -18,13 +19,15 @@ module Crystal::System::FileDescriptor
1819 STDOUT_HANDLE = 1
1920 STDERR_HANDLE = 2
2021
22+ @fd_lock = FdLock .new
23+
2124 private def system_blocking?
22- flags = system_fcntl( LibC ::F_GETFL )
25+ flags = FileDescriptor .fcntl(fd, LibC ::F_GETFL )
2326 ! flags.bits_set? LibC ::O_NONBLOCK
2427 end
2528
2629 private def system_blocking= (value )
27- FileDescriptor .set_blocking(fd, value)
30+ @fd_lock .reference { FileDescriptor .set_blocking(fd, value) }
2831 end
2932
3033 protected def self.get_blocking (fd : Handle )
@@ -56,7 +59,7 @@ module Crystal::System::FileDescriptor
5659 end
5760
5861 private def system_close_on_exec?
59- flags = system_fcntl( LibC ::F_GETFD )
62+ flags = FileDescriptor .fcntl(fd, LibC ::F_GETFD )
6063 flags.bits_set? LibC ::FD_CLOEXEC
6164 end
6265
@@ -76,7 +79,7 @@ module Crystal::System::FileDescriptor
7679 end
7780
7881 private def system_fcntl (cmd , arg = 0 )
79- FileDescriptor .fcntl(fd, cmd, arg)
82+ @fd_lock .reference { FileDescriptor .fcntl(fd, cmd, arg) }
8083 end
8184
8285 def self.system_info (fd )
@@ -91,11 +94,11 @@ module Crystal::System::FileDescriptor
9194 end
9295
9396 private def system_info
94- FileDescriptor .system_info fd
97+ @fd_lock .reference { FileDescriptor .system_info(fd) }
9598 end
9699
97100 private def system_seek (offset , whence : IO ::Seek ) : Nil
98- seek_value = LibC .lseek(fd, offset, whence)
101+ seek_value = @fd_lock .reference { LibC .lseek(fd, offset, whence) }
99102
100103 if seek_value == -1
101104 raise IO ::Error .from_errno " Unable to seek" , target: self
@@ -113,19 +116,23 @@ module Crystal::System::FileDescriptor
113116 end
114117
115118 private def system_reopen (other : IO ::FileDescriptor )
116- {% if LibC .has_method?(:dup3 ) % }
117- flags = other.close_on_exec? ? LibC ::O_CLOEXEC : 0
118- if LibC .dup3(other.fd, fd, flags) == -1
119- raise IO ::Error .from_errno(" Could not reopen file descriptor" )
120- end
121- {% else % }
122- Process .lock_read do
123- if LibC .dup2(other.fd, fd) == -1
124- raise IO ::Error .from_errno(" Could not reopen file descriptor" )
125- end
126- self .close_on_exec = other.close_on_exec?
119+ other.@fd_lock .reference do
120+ @fd_lock .reference do
121+ {% if LibC .has_method?(:dup3 ) % }
122+ flags = other.close_on_exec? ? LibC ::O_CLOEXEC : 0
123+ if LibC .dup3(other.fd, fd, flags) == -1
124+ raise IO ::Error .from_errno(" Could not reopen file descriptor" )
125+ end
126+ {% else % }
127+ Process .lock_read do
128+ if LibC .dup2(other.fd, fd) == -1
129+ raise IO ::Error .from_errno(" Could not reopen file descriptor" )
130+ end
131+ self .close_on_exec = other.close_on_exec?
132+ end
133+ {% end % }
127134 end
128- { % end % }
135+ end
129136
130137 # Mark the handle open, since we had to have dup'd a live handle.
131138 @closed = false
@@ -134,8 +141,9 @@ module Crystal::System::FileDescriptor
134141 end
135142
136143 private def system_close
137- event_loop.before_close(self )
138- event_loop.close(self )
144+ if @fd_lock .try_close? { event_loop.before_close(self ) }
145+ event_loop.close(self )
146+ end
139147 end
140148
141149 def file_descriptor_close (& ) : Nil
@@ -196,7 +204,7 @@ module Crystal::System::FileDescriptor
196204 end
197205
198206 private def flock (op ) : Bool
199- if 0 == LibC .flock(fd, op)
207+ if 0 == @fd_lock .reference { LibC .flock(fd, op) }
200208 true
201209 else
202210 errno = Errno .value
@@ -209,7 +217,7 @@ module Crystal::System::FileDescriptor
209217 end
210218
211219 private def system_fsync (flush_metadata = true ) : Nil
212- ret =
220+ ret = @fd_lock .reference do
213221 if flush_metadata
214222 LibC .fsync(fd)
215223 else
@@ -219,6 +227,7 @@ module Crystal::System::FileDescriptor
219227 LibC .fdatasync(fd)
220228 {% end % }
221229 end
230+ end
222231
223232 if ret != 0
224233 raise IO ::Error .from_errno(" Error syncing file" , target: self )
@@ -246,7 +255,9 @@ module Crystal::System::FileDescriptor
246255 end
247256
248257 def self.pread (file, buffer, offset)
249- bytes_read = LibC .pread(file.fd, buffer, buffer.size, offset).to_i64
258+ bytes_read = file.@fd_lock .reference do
259+ LibC .pread(file.fd, buffer, buffer.size, offset).to_i64
260+ end
250261
251262 if bytes_read == -1
252263 raise IO ::Error .from_errno(" Error reading file" , target: file)
@@ -351,7 +362,7 @@ module Crystal::System::FileDescriptor
351362 @[AlwaysInline ]
352363 private def system_tcsetattr (optional_actions , termios_p )
353364 {% if LibC .has_method?(:tcsetattr ) % }
354- LibC .tcsetattr(fd, optional_actions, termios_p)
365+ @fd_lock .reference { LibC .tcsetattr(fd, optional_actions, termios_p) }
355366 {% else % }
356367 optional_actions = optional_actions.value if optional_actions.is_a?(Termios ::LineControl )
357368 cmd = case optional_actions
@@ -366,7 +377,7 @@ module Crystal::System::FileDescriptor
366377 return LibC ::Int .new(-1 )
367378 end
368379
369- LibC .ioctl(fd, cmd, termios_p)
380+ @fd_lock .reference { LibC .ioctl(fd, cmd, termios_p) }
370381 {% end % }
371382 end
372383
@@ -385,4 +396,12 @@ module Crystal::System::FileDescriptor
385396 {% end % }
386397 termios
387398 end
399+
400+ private def system_read (slice : Bytes ) : Int32
401+ @fd_lock .read { event_loop.read(self , slice) }
402+ end
403+
404+ private def system_write (slice : Bytes ) : Int32
405+ @fd_lock .write { event_loop.write(self , slice) }
406+ end
388407end
0 commit comments