https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=d52d983e5b69457c706c34097a328a7678107b1a

commit d52d983e5b69457c706c34097a328a7678107b1a
Author:     Corinna Vinschen <[email protected]>
AuthorDate: Tue Jan 28 16:50:12 2025 +0100
Commit:     Corinna Vinschen <[email protected]>
CommitDate: Tue Jan 28 16:50:12 2025 +0100

    Cygwin: implement posix_close
    
    per
    https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_close.html
    
    Add a flag value to fhandler_*::close() and close_with_arch() methods,
    taking -1 as default argument, used to indicate default close(2)
    behaviour.
    
    The only fhandlers capable of returning EINTR are the INET based
    socket fhandlers.  Handle -1 and POSIX_CLOSE_RESTART equivalent,
    making close() and posix_close(POSIX_CLOSE_RESTART) behaving
    identically.
    
    Signed-off-by: Corinna Vinschen <[email protected]>

Diff:
---
 winsup/cygwin/cygwin.din                |  1 +
 winsup/cygwin/fhandler/base.cc          |  6 ++--
 winsup/cygwin/fhandler/clipboard.cc     |  2 +-
 winsup/cygwin/fhandler/console.cc       |  2 +-
 winsup/cygwin/fhandler/dev.cc           |  2 +-
 winsup/cygwin/fhandler/disk_file.cc     |  2 +-
 winsup/cygwin/fhandler/dsp.cc           |  2 +-
 winsup/cygwin/fhandler/fifo.cc          |  2 +-
 winsup/cygwin/fhandler/floppy.cc        |  2 +-
 winsup/cygwin/fhandler/mqueue.cc        |  2 +-
 winsup/cygwin/fhandler/netdrive.cc      |  2 +-
 winsup/cygwin/fhandler/pipe.cc          |  2 +-
 winsup/cygwin/fhandler/procsys.cc       |  2 +-
 winsup/cygwin/fhandler/pty.cc           |  6 ++--
 winsup/cygwin/fhandler/registry.cc      |  2 +-
 winsup/cygwin/fhandler/socket_inet.cc   | 19 +++++++++--
 winsup/cygwin/fhandler/socket_local.cc  |  2 +-
 winsup/cygwin/fhandler/socket_unix.cc   |  2 +-
 winsup/cygwin/fhandler/tape.cc          |  2 +-
 winsup/cygwin/fhandler/timerfd.cc       |  2 +-
 winsup/cygwin/fhandler/virtual.cc       |  2 +-
 winsup/cygwin/include/cygwin/version.h  |  3 +-
 winsup/cygwin/local_includes/fhandler.h | 52 ++++++++++++++---------------
 winsup/cygwin/syscalls.cc               | 58 +++++++++++++++++++++++++++++----
 24 files changed, 120 insertions(+), 59 deletions(-)

diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din
index 95a21378b263..deac201c085c 100644
--- a/winsup/cygwin/cygwin.din
+++ b/winsup/cygwin/cygwin.din
@@ -1044,6 +1044,7 @@ pipe SIGFE
 pipe2 SIGFE
 poll SIGFE
 popen SIGFE
+posix_close SIGFE
 posix_fadvise SIGFE
 posix_fallocate SIGFE
 posix_getdents SIGFE
diff --git a/winsup/cygwin/fhandler/base.cc b/winsup/cygwin/fhandler/base.cc
index b889157d6a14..8f3dbd4ed51a 100644
--- a/winsup/cygwin/fhandler/base.cc
+++ b/winsup/cygwin/fhandler/base.cc
@@ -1255,7 +1255,7 @@ fhandler_base::pwrite (void *, size_t, off_t, void *)
 }
 
 int
-fhandler_base::close_with_arch ()
+fhandler_base::close_with_arch (int flag)
 {
   int res;
   fhandler_base *fh;
@@ -1285,7 +1285,7 @@ fhandler_base::close_with_arch ()
     }
 
   cleanup ();
-  res = fh->close ();
+  res = fh->close (flag);
   if (archetype)
     {
       cygheap->fdtab.delete_archetype (archetype);
@@ -1304,7 +1304,7 @@ fhandler_base::cleanup ()
 }
 
 int
-fhandler_base::close ()
+fhandler_base::close (int flag)
 {
   int res = -1;
 
diff --git a/winsup/cygwin/fhandler/clipboard.cc 
b/winsup/cygwin/fhandler/clipboard.cc
index 376d43440749..12691c7c169d 100644
--- a/winsup/cygwin/fhandler/clipboard.cc
+++ b/winsup/cygwin/fhandler/clipboard.cc
@@ -341,7 +341,7 @@ fhandler_dev_clipboard::lseek (off_t offset, int whence)
 }
 
 int
-fhandler_dev_clipboard::close ()
+fhandler_dev_clipboard::close (int flag)
 {
   if (!have_execed)
     {
diff --git a/winsup/cygwin/fhandler/console.cc 
b/winsup/cygwin/fhandler/console.cc
index c6c261420e4b..7aa09b0f5fca 100644
--- a/winsup/cygwin/fhandler/console.cc
+++ b/winsup/cygwin/fhandler/console.cc
@@ -1970,7 +1970,7 @@ fhandler_console::post_open_setup (int fd)
 }
 
 int
-fhandler_console::close ()
+fhandler_console::close (int flag)
 {
   debug_printf ("closing: %p, %p", get_handle (), get_output_handle ());
 
diff --git a/winsup/cygwin/fhandler/dev.cc b/winsup/cygwin/fhandler/dev.cc
index c6bda5654d2a..8266397c3ed5 100644
--- a/winsup/cygwin/fhandler/dev.cc
+++ b/winsup/cygwin/fhandler/dev.cc
@@ -59,7 +59,7 @@ fhandler_dev::open (int flags, mode_t mode)
 }
 
 int
-fhandler_dev::close ()
+fhandler_dev::close (int flag)
 {
   return fhandler_disk_file::close ();
 }
diff --git a/winsup/cygwin/fhandler/disk_file.cc 
b/winsup/cygwin/fhandler/disk_file.cc
index f41198ec0f8a..d54d3747eae6 100644
--- a/winsup/cygwin/fhandler/disk_file.cc
+++ b/winsup/cygwin/fhandler/disk_file.cc
@@ -1654,7 +1654,7 @@ fhandler_disk_file::open (int flags, mode_t mode)
 }
 
 int
-fhandler_disk_file::close ()
+fhandler_disk_file::close (int flag)
 {
   /* Close extra pread/pwrite handle, if it exists. */
   if (prw_handle)
diff --git a/winsup/cygwin/fhandler/dsp.cc b/winsup/cygwin/fhandler/dsp.cc
index 605a048f3964..13a9c75c300f 100644
--- a/winsup/cygwin/fhandler/dsp.cc
+++ b/winsup/cygwin/fhandler/dsp.cc
@@ -1230,7 +1230,7 @@ fhandler_dev_dsp::close_audio_out (bool immediately)
 }
 
 int
-fhandler_dev_dsp::close ()
+fhandler_dev_dsp::close (int flag)
 {
   debug_printf ("audio_in=%p audio_out=%p", audio_in_, audio_out_);
   being_closed = true;
diff --git a/winsup/cygwin/fhandler/fifo.cc b/winsup/cygwin/fhandler/fifo.cc
index 7a03894fa6c8..15117db6eb35 100644
--- a/winsup/cygwin/fhandler/fifo.cc
+++ b/winsup/cygwin/fhandler/fifo.cc
@@ -1522,7 +1522,7 @@ fhandler_fifo::cancel_reader_thread ()
 }
 
 int
-fhandler_fifo::close ()
+fhandler_fifo::close (int flag)
 {
   isclosed (true);
   if (select_sem)
diff --git a/winsup/cygwin/fhandler/floppy.cc b/winsup/cygwin/fhandler/floppy.cc
index e883ab697f89..082a2736fa86 100644
--- a/winsup/cygwin/fhandler/floppy.cc
+++ b/winsup/cygwin/fhandler/floppy.cc
@@ -357,7 +357,7 @@ fhandler_dev_floppy::open (int flags, mode_t)
 }
 
 int
-fhandler_dev_floppy::close ()
+fhandler_dev_floppy::close (int flag)
 {
   int ret = fhandler_dev_raw::close ();
 
diff --git a/winsup/cygwin/fhandler/mqueue.cc b/winsup/cygwin/fhandler/mqueue.cc
index 2bf2cb0ea74b..f2aeb56a96b9 100644
--- a/winsup/cygwin/fhandler/mqueue.cc
+++ b/winsup/cygwin/fhandler/mqueue.cc
@@ -559,7 +559,7 @@ fhandler_mqueue::ioctl (unsigned int cmd, void *buf)
 }
 
 int
-fhandler_mqueue::close ()
+fhandler_mqueue::close (int flag)
 {
   __try
     {
diff --git a/winsup/cygwin/fhandler/netdrive.cc 
b/winsup/cygwin/fhandler/netdrive.cc
index 90e5a22175d8..f9412da2f0d3 100644
--- a/winsup/cygwin/fhandler/netdrive.cc
+++ b/winsup/cygwin/fhandler/netdrive.cc
@@ -580,7 +580,7 @@ fhandler_netdrive::open (int flags, mode_t mode)
 }
 
 int
-fhandler_netdrive::close ()
+fhandler_netdrive::close (int flag)
 {
   /* Skip fhandler_virtual::close, which is a no-op. */
   return fhandler_base::close ();
diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc
index d76a4e74ea98..074cb50cafaa 100644
--- a/winsup/cygwin/fhandler/pipe.cc
+++ b/winsup/cygwin/fhandler/pipe.cc
@@ -759,7 +759,7 @@ fhandler_pipe::dup (fhandler_base *child, int flags)
 }
 
 int
-fhandler_pipe::close ()
+fhandler_pipe::close (int flag)
 {
   isclosed (true);
   if (select_sem)
diff --git a/winsup/cygwin/fhandler/procsys.cc 
b/winsup/cygwin/fhandler/procsys.cc
index 4fa00481ad45..aa021e89c704 100644
--- a/winsup/cygwin/fhandler/procsys.cc
+++ b/winsup/cygwin/fhandler/procsys.cc
@@ -472,7 +472,7 @@ fhandler_procsys::open (int flags, mode_t mode)
 }
 
 int
-fhandler_procsys::close ()
+fhandler_procsys::close (int flag)
 {
   if (!nohandle ())
     NtClose (get_handle ());
diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index 4f0f718127a7..ac00a280b863 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -981,7 +981,7 @@ fhandler_pty_slave::cleanup ()
 }
 
 int
-fhandler_pty_slave::close ()
+fhandler_pty_slave::close (int flag)
 {
   termios_printf ("closing last open %s handle", ttyname ());
   if (inuse && !CloseHandle (inuse))
@@ -1957,7 +1957,7 @@ fhandler_pty_common::lseek (off_t, int)
 }
 
 int
-fhandler_pty_common::close ()
+fhandler_pty_common::close (int flag)
 {
   termios_printf ("pty%d <%p,%p> closing",
                  get_minor (), get_handle (), get_output_handle ());
@@ -2004,7 +2004,7 @@ fhandler_pty_master::cleanup ()
 }
 
 int
-fhandler_pty_master::close ()
+fhandler_pty_master::close (int flag)
 {
   OBJECT_BASIC_INFORMATION obi;
   NTSTATUS status;
diff --git a/winsup/cygwin/fhandler/registry.cc 
b/winsup/cygwin/fhandler/registry.cc
index ac413af9bb56..26ee05fe9e50 100644
--- a/winsup/cygwin/fhandler/registry.cc
+++ b/winsup/cygwin/fhandler/registry.cc
@@ -898,7 +898,7 @@ out:
 }
 
 int
-fhandler_registry::close ()
+fhandler_registry::close (int flag)
 {
   int res = fhandler_virtual::close ();
   if (res != 0)
diff --git a/winsup/cygwin/fhandler/socket_inet.cc 
b/winsup/cygwin/fhandler/socket_inet.cc
index 63cc498f17b6..22dfed63d6ca 100644
--- a/winsup/cygwin/fhandler/socket_inet.cc
+++ b/winsup/cygwin/fhandler/socket_inet.cc
@@ -1035,10 +1035,25 @@ fhandler_socket_wsock::shutdown (int how)
 }
 
 int
-fhandler_socket_wsock::close ()
+fhandler_socket_wsock::close (int flag)
 {
   int res = 0;
+  unsigned wait_flags;
 
+  switch (flag)
+    {
+    /* See comment preceeding close() functions in syscalls.cc.  Given
+       WSAEWOULDBLOCK leaves the socket open, the default behaviour is
+       equivalent to posix_close w/ POSIX_CLOSE_RESTART. */
+    case -1:
+    case POSIX_CLOSE_RESTART:
+      wait_flags = cw_cancel | cw_sig;
+      break;
+    case 0:
+    default:   /* shouldn't happen, already handled in syscall.cc:__close() */
+      wait_flags = cw_cancel | cw_sig | cw_sig_restart;
+      break;
+    }
   release_events ();
   while ((res = ::closesocket (get_socket ())) != 0)
     {
@@ -1048,7 +1063,7 @@ fhandler_socket_wsock::close ()
          res = -1;
          break;
        }
-      if (cygwait (10) == WAIT_SIGNALED)
+      if (cygwait (NULL, 10, wait_flags) == WAIT_SIGNALED)
        {
          set_errno (EINTR);
          res = -1;
diff --git a/winsup/cygwin/fhandler/socket_local.cc 
b/winsup/cygwin/fhandler/socket_local.cc
index e4a88169b0b2..270a1ef31c82 100644
--- a/winsup/cygwin/fhandler/socket_local.cc
+++ b/winsup/cygwin/fhandler/socket_local.cc
@@ -649,7 +649,7 @@ fhandler_socket_local::open (int flags, mode_t mode)
 }
 
 int
-fhandler_socket_local::close ()
+fhandler_socket_local::close (int flag)
 {
   if (get_flags () & O_PATH)
     return fhandler_base::close ();
diff --git a/winsup/cygwin/fhandler/socket_unix.cc 
b/winsup/cygwin/fhandler/socket_unix.cc
index 0cd97f62500b..aacaa5c6290a 100644
--- a/winsup/cygwin/fhandler/socket_unix.cc
+++ b/winsup/cygwin/fhandler/socket_unix.cc
@@ -1795,7 +1795,7 @@ fhandler_socket_unix::open (int flags, mode_t mode)
 }
 
 int
-fhandler_socket_unix::close ()
+fhandler_socket_unix::close (int flag)
 {
   if (get_flags () & O_PATH)
     return fhandler_base::close ();
diff --git a/winsup/cygwin/fhandler/tape.cc b/winsup/cygwin/fhandler/tape.cc
index 732fd1bb7f55..deed4e3d6ac0 100644
--- a/winsup/cygwin/fhandler/tape.cc
+++ b/winsup/cygwin/fhandler/tape.cc
@@ -1249,7 +1249,7 @@ fhandler_dev_tape::open (int flags, mode_t)
 }
 
 int
-fhandler_dev_tape::close ()
+fhandler_dev_tape::close (int flag)
 {
   int ret = 0;
   int cret = 0;
diff --git a/winsup/cygwin/fhandler/timerfd.cc 
b/winsup/cygwin/fhandler/timerfd.cc
index 9269494dbd2c..982950d0054b 100644
--- a/winsup/cygwin/fhandler/timerfd.cc
+++ b/winsup/cygwin/fhandler/timerfd.cc
@@ -241,7 +241,7 @@ fhandler_timerfd::fixup_after_exec ()
 }
 
 int
-fhandler_timerfd::close ()
+fhandler_timerfd::close (int flag)
 {
   int ret = -1;
 
diff --git a/winsup/cygwin/fhandler/virtual.cc 
b/winsup/cygwin/fhandler/virtual.cc
index 90653fbf9a2e..4a7b2b725524 100644
--- a/winsup/cygwin/fhandler/virtual.cc
+++ b/winsup/cygwin/fhandler/virtual.cc
@@ -162,7 +162,7 @@ fhandler_virtual::dup (fhandler_base * child, int flags)
 }
 
 int
-fhandler_virtual::close ()
+fhandler_virtual::close (int flag)
 {
   if (!have_execed)
     {
diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index 4dc3e0fcf596..02280746d6c2 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -492,12 +492,13 @@ details. */
   355: Implement setproctitle.
   356: Export posix_spawn_file_actions_addchdir and
        posix_spawn_file_actions_addfchdir.
+  357: Export posix_close.
 
   Note that we forgot to bump the api for ualarm, strtoll, strtoull,
   sigaltstack, sethostname. */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 356
+#define CYGWIN_VERSION_API_MINOR 357
 
 /* There is also a compatibity version number associated with the shared memory
    regions.  It is incremented when incompatible changes are made to the shared
diff --git a/winsup/cygwin/local_includes/fhandler.h 
b/winsup/cygwin/local_includes/fhandler.h
index 3550481b5a53..273ee31e1fe4 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -364,8 +364,8 @@ class fhandler_base
   void set_unique_id (int64_t u) { unique_id = u; }
   void set_unique_id () { NtAllocateLocallyUniqueId ((PLUID) &unique_id); }
 
-  int close_with_arch ();
-  virtual int close ();
+  int close_with_arch (int flag = -1);
+  virtual int close (int flag = -1);
   virtual void cleanup ();
   int _archetype_usecount (const char *fn, int ln, int n)
   {
@@ -602,7 +602,7 @@ class fhandler_socket: public fhandler_base
   virtual int getsockname (struct sockaddr *name, int *namelen) = 0;
   virtual int getpeername (struct sockaddr *name, int *namelen) = 0;
   virtual int shutdown (int how) = 0;
-  virtual int close () = 0;
+  virtual int close (int flag = -1) = 0;
   virtual int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid);
   virtual ssize_t recvfrom (void *ptr, size_t len, int flags,
                            struct sockaddr *from, int *fromlen) = 0;
@@ -731,7 +731,7 @@ class fhandler_socket_wsock: public fhandler_socket
   ssize_t write (const void *ptr, size_t len);
   ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
   int shutdown (int how);
-  int close ();
+  int close (int flag = -1);
 
   int ioctl (unsigned int cmd, void *);
   int fcntl (int cmd, intptr_t);
@@ -869,7 +869,7 @@ class fhandler_socket_local: public fhandler_socket_wsock
                  __socklen_t *optlen);
 
   int open (int flags, mode_t mode = 0);
-  int close ();
+  int close (int flag = -1);
   int fcntl (int cmd, intptr_t);
   int fstat (struct stat *buf);
   int fstatvfs (struct statvfs *buf);
@@ -1132,7 +1132,7 @@ class fhandler_socket_unix : public fhandler_socket
   int getpeername (struct sockaddr *name, int *namelen);
   int shutdown (int how);
   int open (int flags, mode_t mode = 0);
-  int close ();
+  int close (int flag = -1);
   int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid);
   ssize_t recvmsg (struct msghdr *msg, int flags);
   ssize_t recvfrom (void *ptr, size_t len, int flags,
@@ -1237,7 +1237,7 @@ public:
   void fixup_after_fork (HANDLE);
   int dup (fhandler_base *child, int);
   void set_close_on_exec (bool val);
-  int close ();
+  int close (int flag = -1);
   void raw_read (void *ptr, size_t& len);
   int ioctl (unsigned int cmd, void *);
   int fstat (struct stat *buf);
@@ -1286,7 +1286,7 @@ struct fifo_client_handler
   fifo_client_connect_state _state;
   bool last_read;  /* true if our last successful read was from this client. */
   fifo_client_handler () : h (NULL), _state (fc_unknown), last_read (false) {}
-  void close () { NtClose (h); }
+  void close (int flag = -1) { NtClose (h); }
   fifo_client_connect_state get_state () const { return _state; }
   void set_state (fifo_client_connect_state s) { _state = s; }
   /* Query O/S.  Return previous state. */
@@ -1496,7 +1496,7 @@ public:
 
   int open (int, mode_t);
   off_t lseek (off_t offset, int whence);
-  int close ();
+  int close (int flag = -1);
   int fcntl (int cmd, intptr_t);
   int dup (fhandler_base *child, int);
   bool isfifo () const { return true; }
@@ -1614,7 +1614,7 @@ class fhandler_dev_floppy: public fhandler_dev_raw
   fhandler_dev_floppy ();
 
   int open (int flags, mode_t mode = 0);
-  int close ();
+  int close (int flag = -1);
   int dup (fhandler_base *child, int);
   void raw_read (void *ptr, size_t& ulen);
   ssize_t raw_write (const void *ptr, size_t ulen);
@@ -1655,7 +1655,7 @@ class fhandler_dev_tape: public fhandler_dev_raw
   fhandler_dev_tape ();
 
   int open (int flags, mode_t mode = 0);
-  virtual int close ();
+  virtual int close (int flag = -1);
 
   void raw_read (void *ptr, size_t& ulen);
   ssize_t raw_write (const void *ptr, size_t ulen);
@@ -1708,7 +1708,7 @@ class fhandler_disk_file: public fhandler_base
   fhandler_disk_file (path_conv &pc);
 
   int open (int flags, mode_t mode);
-  int close ();
+  int close (int flag = -1);
   int fcntl (int cmd, intptr_t);
   int dup (fhandler_base *child, int);
   void fixup_after_fork (HANDLE parent);
@@ -1772,7 +1772,7 @@ class fhandler_dev: public fhandler_disk_file
 public:
   fhandler_dev ();
   int open (int flags, mode_t mode);
-  int close ();
+  int close (int flag = -1);
   int fstat (struct stat *buf);
   int fstatvfs (struct statvfs *buf);
   int rmdir ();
@@ -2259,7 +2259,7 @@ private:
   void read (void *ptr, size_t& len);
   ssize_t write (const void *ptr, size_t len);
   void doecho (const void *str, DWORD len);
-  int close ();
+  int close (int flag = -1);
   static bool exists ()
     {
       acquire_attach_mutex (mutex_timeout);
@@ -2388,7 +2388,7 @@ class fhandler_pty_common: public fhandler_termios
   DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms);
   void __release_output_mutex (const char *fn, int ln);
 
-  int close ();
+  int close (int flag = -1);
   off_t lseek (off_t, int);
   bool bytes_available (DWORD& n);
   void set_close_on_exec (bool val);
@@ -2459,7 +2459,7 @@ class fhandler_pty_slave: public fhandler_pty_common
   int tcgetattr (struct termios *t);
   int tcflush (int);
   int ioctl (unsigned int cmd, void *);
-  int close ();
+  int close (int flag = -1);
   void cleanup ();
   int dup (fhandler_base *child, int);
   void fixup_after_fork (HANDLE parent);
@@ -2568,7 +2568,7 @@ public:
   bool open_setup (int flags);
   ssize_t write (const void *ptr, size_t len);
   void read (void *ptr, size_t& len);
-  int close ();
+  int close (int flag = -1);
   void cleanup ();
 
   int tcsetattr (int a, const struct termios *t);
@@ -2729,7 +2729,7 @@ class fhandler_dev_clipboard: public fhandler_base
   ssize_t write (const void *ptr, size_t len);
   void read (void *ptr, size_t& len);
   off_t lseek (off_t offset, int whence);
-  int close ();
+  int close (int flag = -1);
 
   int dup (fhandler_base *child, int);
   void fixup_after_exec ();
@@ -2766,7 +2766,7 @@ class fhandler_windows: public fhandler_base
   void read (void *ptr, size_t& len);
   int ioctl (unsigned int cmd, void *);
   off_t lseek (off_t, int) { return 0; }
-  int close () { return 0; }
+  int close (int flag = -1) { return 0; }
 
   select_record *select_read (select_stuff *);
   select_record *select_write (select_stuff *);
@@ -2845,7 +2845,7 @@ class fhandler_dev_dsp: public fhandler_base
   void read (void *, size_t&);
   int ioctl (unsigned int, void *);
   int fcntl (int cmd, intptr_t);
-  int close ();
+  int close (int flag = -1);
   void fixup_after_fork (HANDLE);
   void fixup_after_exec ();
   bool open_setup (int);
@@ -2918,7 +2918,7 @@ class fhandler_virtual : public fhandler_base
   off_t lseek (off_t, int);
   int dup (fhandler_base *child, int);
   int open (int flags, mode_t mode = 0);
-  int close ();
+  int close (int flag = -1);
   int fstatvfs (struct statvfs *buf);
   int fchmod (mode_t mode);
   int fchown (uid_t uid, gid_t gid);
@@ -2991,7 +2991,7 @@ class fhandler_procsys: public fhandler_virtual
   void seekdir (DIR *, long);
   int closedir (DIR *);
   int open (int flags, mode_t mode = 0);
-  int close ();
+  int close (int flag = -1);
   void read (void *ptr, size_t& len);
   ssize_t write (const void *ptr, size_t len);
   int fstat (struct stat *buf);
@@ -3055,7 +3055,7 @@ class fhandler_netdrive: public fhandler_virtual
   void rewinddir (DIR *);
   int closedir (DIR *);
   int open (int flags, mode_t mode = 0);
-  int close ();
+  int close (int flag = -1);
   int fstat (struct stat *buf);
 
   fhandler_netdrive (void *) {}
@@ -3096,7 +3096,7 @@ class fhandler_registry: public fhandler_proc
   int open (int flags, mode_t mode = 0);
   int fstat (struct stat *buf);
   bool fill_filebuf ();
-  int close ();
+  int close (int flag = -1);
   int dup (fhandler_base *child, int);
 
   fhandler_registry (void *) {}
@@ -3348,7 +3348,7 @@ class fhandler_timerfd : public fhandler_base
   ssize_t write (const void *, size_t);
   int dup (fhandler_base *child, int);
   int ioctl (unsigned int, void *);
-  int close ();
+  int close (int flag = -1);
 
   HANDLE get_timerfd_handle ();
 
@@ -3441,7 +3441,7 @@ public:
   int dup (fhandler_base *, int);
   int fcntl (int cmd, intptr_t);
   int ioctl (unsigned int, void *);
-  int close ();
+  int close (int flag = -1);
 
   void copy_from (fhandler_base *x)
   {
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 4890131b762b..c93bf4c95ce8 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1678,13 +1678,27 @@ lseek (int fd, off_t pos, int dir)
   return res;
 }
 
-extern "C" int
-close (int fd)
+/* Takes three flag values:
+
+   -1: default behaviour, called from close(2).
+
+    0: called via posix_close (0), i.e., the call shall not return -1 with
+       errno set to [EINTR], which implies that fildes will always be closed
+       (except for [EBADF], where fildes was invalid).
+
+    POSIX_CLOSE_RESTART: called via posix_close (POSIX_CLOSE_RESTART), i. e.
+       if the call is interrupted by a signal that is to be caught, the call
+       may return -1 with errno set to [EINTR], in which case fildes
+       shall be left open; however, it is unspecified whether fildes can
+       subsequently be passed to any function except close() or posix_close()
+       without error.
+
+     Note that POSIX_CLOSE_RESTART means the opposite of SA_RESTART! */
+static inline int
+__close (int fd, int flag)
 {
   int res;
 
-  syscall_printf ("close(%d)", fd);
-
   pthread_testcancel ();
 
   cygheap_fdget cfd (fd, true);
@@ -1692,14 +1706,44 @@ close (int fd)
     res = -1;
   else
     {
-      res = cfd->close_with_arch ();
-      cfd.release ();
+      res = cfd->close_with_arch (flag);
+      if (res != EINTR)
+       cfd.release ();
     }
 
-  syscall_printf ("%R = close(%d)", res, fd);
   return res;
 }
 
+extern "C" int
+close (int fd)
+{
+  syscall_printf ("close(%d)", fd);
+  int ret =  __close (fd, -1);
+  syscall_printf ("%R = close(%d)", ret, fd);
+  return ret;
+}
+
+extern "C" int
+posix_close (int fd, int flag)
+{
+   int real_flag = flag;
+
+  /* POSIX-1.2024 says: If flag is invalid, posix_close() may fail with errno
+     set to [EINVAL], but shall otherwise behave as if flag had been 0 and
+     close fd. */
+  if (real_flag != 0 && real_flag != POSIX_CLOSE_RESTART)
+    real_flag = 0;
+  syscall_printf ("posix_close(%d, %d)", fd, flag);
+  int ret = __close (fd, real_flag);
+  if (!ret && flag != real_flag)
+    {
+      set_errno (EINVAL);
+      ret = -1;
+    }
+  syscall_printf ("%R = posix_close(%d, %d)", ret, fd, flag);
+  return ret;
+}
+
 extern "C" int
 isatty (int fd)
 {

Reply via email to