New FAQ entry about permissions since Cygwin 1.7.34

2015-10-06 Thread Ken Brown
There have been several recent threads on the cygwin list stemming from 
the permissions change in 1.7.34.  I've pointed people to the FAQ about 
ssh public key authentication, which is not the first place where 
someone with this problem is likely to look.  The following patch 
attempts to remedy this:


---
 winsup/doc/ChangeLog |  4 
 winsup/doc/faq-using.xml | 42 ++
 2 files changed, 46 insertions(+)

diff --git a/winsup/doc/ChangeLog b/winsup/doc/ChangeLog
index 35935be..7e85a76 100644
--- a/winsup/doc/ChangeLog
+++ b/winsup/doc/ChangeLog
@@ -1,3 +1,7 @@
+2015-10-06  Ken Brown  
+
+   * faq-using.xml (faq.using.same-with-permissions): New entry.
+
 2015-09-07  Brian Inglis  

* faq-using.xml (faq.using.man): Replace makewhatis with mandb.
diff --git a/winsup/doc/faq-using.xml b/winsup/doc/faq-using.xml
index 7656880..0564504 100644
--- a/winsup/doc/faq-using.xml
+++ b/winsup/doc/faq-using.xml
@@ -1183,6 +1183,48 @@ Users group instead.

 

+
+Why do my files have extra permissions after updating 
to Cygwin 1.7.34?

+
+
+The problem is exactly the same as with the key files of SSH.  See
+.
+
+The solution is the same:
+
+
+  $ ls -l *
+  -rw-rwxr--+ 1 user group 42 Nov 12  2010 file1
+  -rw-rwxr--+ 1 user group 42 Nov 12  2010 file2
+  $ setfacl -b *
+  $ ls -l *
+  -rw-r--r--  1 user group 42 Nov 12  2010 file1
+  -rw-r--r--  1 user group 42 Nov 12  2010 file2
+
+
+You may find that newly-created files also have unexpected
+permissions:
+
+
+  $ touch foo
+  $ ls -l foo
+  -rw-rwxr--+ 1 user group 42 Nov 12  2010 foo
+
+
+This probably means that the directory in which you're creating
+the files has unwanted default ACL entries that are inherited by
+newly-created files and subdirectories.  The solution is again the
+same:
+
+
+  $ setfacl -b .
+  $ touch bar
+  $ ls -l bar
+  -rw-r--r--  1 user group 42 Nov 12  2010 bar
+
+
+
+
 
 Why do my Tk programs not work anymore?
 
--
2.5.3

Ken


Re: New FAQ entry about permissions since Cygwin 1.7.34

2015-10-20 Thread Ken Brown

On 10/20/2015 3:25 PM, Corinna Vinschen wrote:

Hi Ken,

On Oct  6 16:41, Ken Brown wrote:

There have been several recent threads on the cygwin list stemming from the
permissions change in 1.7.34.  I've pointed people to the FAQ about ssh
public key authentication, which is not the first place where someone with
this problem is likely to look.  The following patch attempts to remedy
this:


Unfortunately it doesn't apply cleanly.  There are weird differences in
whitespaces and a patch-breaking line wrap.  Can you check and resend,
please?


Sorry, my mailer must have messed it up.  Here it is as an attachment.

Ken

From d073a456341cb58d92ce75c2b5b46e1d2a54ec09 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Tue, 6 Oct 2015 16:31:05 -0400
Subject: [PATCH] * winsup/doc/faq-using.xml (faq.using.same-with-permissions):
 New entry.

---
 winsup/doc/ChangeLog |  4 
 winsup/doc/faq-using.xml | 42 ++
 2 files changed, 46 insertions(+)

diff --git a/winsup/doc/ChangeLog b/winsup/doc/ChangeLog
index 35935be..7e85a76 100644
--- a/winsup/doc/ChangeLog
+++ b/winsup/doc/ChangeLog
@@ -1,3 +1,7 @@
+2015-10-06  Ken Brown  
+
+   * faq-using.xml (faq.using.same-with-permissions): New entry.
+
 2015-09-07  Brian Inglis  
 
* faq-using.xml (faq.using.man): Replace makewhatis with mandb.
diff --git a/winsup/doc/faq-using.xml b/winsup/doc/faq-using.xml
index 7656880..4cfc822 100644
--- a/winsup/doc/faq-using.xml
+++ b/winsup/doc/faq-using.xml
@@ -1183,6 +1183,48 @@ Users group instead.
 
 
 
+
+Why do my files have extra permissions after updating to 
Cygwin 1.7.34?
+
+
+The problem is exactly the same as with the key files of SSH.  See
+.
+
+The solution is the same:
+
+
+  $ ls -l *
+  -rw-rwxr--+ 1 user group 42 Nov 12  2010 file1
+  -rw-rwxr--+ 1 user group 42 Nov 12  2010 file2
+  $ setfacl -b *
+  $ ls -l *
+  -rw-r--r--  1 user group 42 Nov 12  2010 file1
+  -rw-r--r--  1 user group 42 Nov 12  2010 file2
+
+
+You may find that newly-created files also have unexpected
+permissions:
+
+
+  $ touch foo
+  $ ls -l foo
+  -rw-rwxr--+ 1 user group 42 Nov 12  2010 foo
+
+
+This probably means that the directory in which you're creating
+the files has unwanted default ACL entries that are inherited by
+newly-created files and subdirectories.  The solution is again the
+same:
+
+
+  $ setfacl -b .
+  $ touch bar
+  $ ls -l bar
+  -rw-r--r--  1 user group 42 Nov 12  2010 bar
+
+
+
+
 
 Why do my Tk programs not work anymore?
 
-- 
2.5.3



Trivial fix to last change

2015-12-11 Thread Ken Brown
cygwin1.dll doesn't build on x86 after the last commit (eed35ef).  The 
trivial patch attached fixes it.


Ken
From 1cd61c54994b2ba6c6ec1d1f8f1249f5f8fd4af3 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Fri, 11 Dec 2015 17:08:28 -0500
Subject: [PATCH] Fix regparm attribute of fhandler_base::fstat_helper

* winsup/cygwin/fhandler_disk_file.cc (fhandler_base::fstat_helper):
Align regparm attribute to declaration in fhandler.h.
---
 winsup/cygwin/ChangeLog | 5 +
 winsup/cygwin/fhandler_disk_file.cc | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 3c9804b..7079baa 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,8 @@
+2015-12-11  Ken Brown  
+
+   * fhandler_disk_file.cc (fhandler_base::fstat_helper): Align
+   regparm attribute to declaration in fhandler.h.
+
 2015-12-10  Corinna Vinschen  
 
* path.h (class path_conv_handle): Use FILE_ALL_INFORMATION instead of
diff --git a/winsup/cygwin/fhandler_disk_file.cc 
b/winsup/cygwin/fhandler_disk_file.cc
index fe9dd03..1dd1b8c 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -428,7 +428,7 @@ fhandler_base::fstat_fs (struct stat *buf)
   return res;
 }
 
-int __reg3
+int __reg2
 fhandler_base::fstat_helper (struct stat *buf)
 {
   IO_STATUS_BLOCK st;
-- 
2.6.2



Fix 'make distclean'

2016-06-05 Thread Ken Brown
Sometimes when a build of Cygwin fails, there will be a message 
suggesting running 'make distclean'.  But this fails to clean the 
winsup/cygwin subdirectory, and the build still fails.


On the other hand, 'make clean' in winsup/cygwin removes two source 
files, which have to be restored before one can rebuild.


The attached patch fixes both problems.

Ken
From 71c16ecc3126a41ae41cbf354428c64282952951 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Sun, 5 Jun 2016 12:58:22 -0400
Subject: [PATCH] Allow 'make distclean' to clean winsup/cygwin
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

But don’t let it remove source files.
---
 winsup/Makefile.in| 4 ++--
 winsup/cygwin/Makefile.in | 7 ---
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/winsup/Makefile.in b/winsup/Makefile.in
index 1fdf93a..9eca806 100644
--- a/winsup/Makefile.in
+++ b/winsup/Makefile.in
@@ -48,7 +48,7 @@ CLEAN_SUBDIRS=${patsubst %,clean_%,$(SUBDIRS)}
 
 INSTALL_LICENSE:=@INSTALL_LICENSE@
 
-.PHONY: all install clean all-info info install-info install-license check \
+.PHONY: all install clean distclean all-info info install-info install-license 
check \
$(SUBDIRS) $(INSTALL_SUBDIRS) $(CLEAN_SUBDIRS)
 
 .SUFFIXES:
@@ -71,7 +71,7 @@ install-license: CYGWIN_LICENSE COPYING
 
 install: Makefile $(INSTALL_LICENSE) $(INSTALL_SUBDIRS)
 
-clean: $(CLEAN_SUBDIRS)
+clean distclean: $(CLEAN_SUBDIRS)
 
 all-info:
 
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 43919bd..a548368 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -653,14 +653,15 @@ uninstall-man:
rm -f $(DESTDIR)$(mandir)/man7/`basename $$i` ; \
done
 
-clean:
-   -rm -f *.o *.dll *.dbg *.a *.exp junk *.base version.cc *.exe *.d 
*stamp* *_magic.h sigfe.s cygwin.def globals.h $(srcdir)/$(TLSOFFSETS_H) 
$(srcdir)/devices.cc
+clean distclean realclean:
+   -rm -f *.o *.dll *.dbg *.a *.exp junk *.base version.cc *.exe *.d 
*stamp* *_magic.h sigfe.s cygwin.def globals.h
-@$(MAKE) -C ${cygserver_blddir} libclean
 
-maintainer-clean realclean: clean
+maintainer-clean: clean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
-rm -fr configure
+   -rm -f  $(srcdir)/$(TLSOFFSETS_H) $(srcdir)/devices.cc
 
 # Rule to build LDSCRIPT
 $(LDSCRIPT): $(LDSCRIPT).in
-- 
2.8.3



Declaration of crypt

2016-06-08 Thread Ken Brown
According to Posix, including  should bring in the declaration 
of crypt.  The glibc and FreeBSD headers are consistent with this, but 
Cygwin's aren't.


$ cat test.c
#include 

int
main (void)
{
  const char *key = NULL;
  const char *salt = NULL;
  crypt (key, salt);
}

$ gcc -c test.c
test.c: In function ‘main’:
test.c:8:3: warning: implicit declaration of function ‘crypt’ 
[-Wimplicit-function-declaration]

   crypt (key, salt);
   ^

The attached patch is one way to fix this.  It means that cygwin-devel 
would have to require libcrypt-devel.


I'm not sure if I used the right feature-test macro in the patch.  It's 
marked XSI by Posix, but using __XSI_VISIBLE didn't work.


Ken

P.S. Is cygwin-patches OK for this sort of thing, or should I have sent 
it to the newlib list?
From 91ed7816e771a78170555db246e0e35dc6d2ca3e Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Wed, 8 Jun 2016 17:04:06 -0400
Subject: [PATCH] Make  declare crypt

This is mandated by Posix and is done by the glibc and FreeBSD headers.
---
 newlib/libc/include/sys/unistd.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/newlib/libc/include/sys/unistd.h b/newlib/libc/include/sys/unistd.h
index ef00575..ebae5d8 100644
--- a/newlib/libc/include/sys/unistd.h
+++ b/newlib/libc/include/sys/unistd.h
@@ -31,6 +31,9 @@ int _EXFUN(close, (int __fildes ));
 #if __POSIX_VISIBLE >= 199209
 size_t _EXFUN(confstr, (int __name, char *__buf, size_t __len));
 #endif
+#if __BSD_VISIBLE && defined(__CYGWIN__)
+#include 
+#endif
 #if __XSI_VISIBLE && __XSI_VISIBLE < 700
 char *  _EXFUN(ctermid, (char *__s ));
 #endif
-- 
2.8.3



Re: Declaration of crypt

2016-06-09 Thread Ken Brown

On 6/9/2016 5:00 AM, Corinna Vinschen wrote:

Hi Ken,

On Jun  8 17:18, Ken Brown wrote:

According to Posix, including  should bring in the declaration of
crypt.  The glibc and FreeBSD headers are consistent with this, but Cygwin's
aren't.

$ cat test.c
#include 

int
main (void)
{
  const char *key = NULL;
  const char *salt = NULL;
  crypt (key, salt);
}

$ gcc -c test.c
test.c: In function ‘main’:
test.c:8:3: warning: implicit declaration of function ‘crypt’
[-Wimplicit-function-declaration]
   crypt (key, salt);
   ^

The attached patch is one way to fix this.  It means that cygwin-devel would
have to require libcrypt-devel.

I'm not sure if I used the right feature-test macro in the patch.  It's
marked XSI by Posix, but using __XSI_VISIBLE didn't work.


What do you mean by "didn't work"?  __XSI_VISIBLE should be the right
thing to use.  Your application would have to define, e.g.,
_XOPEN_SOURCE before including the file.


Ah, that's what I missed.  I tried defining __XSI_VISIBLE in the test 
file, and I still got the implicit declaration warning.  I see now, 
reading /usr/include/sys/features.h, that __XSI_VISIBLE is a private 
macro and shouldn't have been used in my test.



Another point is the && defined(__CYGWIN__).  This should go away.
We're trying to make the headers more standards compatible without
going into too much detial what targat provides which function.


I wasn't sure that  was portable to all newlib targets.


P.S. Is cygwin-patches OK for this sort of thing, or should I have sent it
to the newlib list?


Ideally to the newlib list, but no worries :)


OK, I'll do that next time.

Revised patch attached.

Ken

From cb8c2454618c1d862b926d61ac95411b384d0414 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Wed, 8 Jun 2016 17:04:06 -0400
Subject: [PATCH] Make  declare crypt

This is mandated by Posix and is done by the glibc and FreeBSD headers.
---
 newlib/libc/include/sys/unistd.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/newlib/libc/include/sys/unistd.h b/newlib/libc/include/sys/unistd.h
index ef00575..0cbb5de 100644
--- a/newlib/libc/include/sys/unistd.h
+++ b/newlib/libc/include/sys/unistd.h
@@ -31,6 +31,9 @@ int _EXFUN(close, (int __fildes ));
 #if __POSIX_VISIBLE >= 199209
 size_t _EXFUN(confstr, (int __name, char *__buf, size_t __len));
 #endif
+#if __XSI_VISIBLE
+#include 
+#endif
 #if __XSI_VISIBLE && __XSI_VISIBLE < 700
 char *  _EXFUN(ctermid, (char *__s ));
 #endif
-- 
2.8.3



Re: Declaration of crypt

2016-06-09 Thread Ken Brown

On 6/9/2016 8:32 AM, Corinna Vinschen wrote:

Can you please define crypt, encrypt and setkey explicitely in unistd.h
per POSIX, rather than including crypt.h?  This would not only be target
independent, it would also be more correct.  As a side effect I will
have to come up with a new version of the crypt package, because our
crypt.h is using a wrong prototypes for setkey (const is missing).


setkey is supposed to be in stdlib.h rather than unistd.h, so I've done 
that.


One minor question about encrypt: The Posix prototype has 'char 
block[64]' as the first argument, but Cygwin's crypt.h simply has 'char 
*block'.  FreeBSD and glibc also use 'char *block', so I did the same. 
Or would you rather follow Posix here?



Thanks a lot and sorry again,


No problem.  Revised patch attached.

Ken

From e6ab8bbf44d1042df3dd9e989967a649523d193d Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Wed, 8 Jun 2016 17:04:06 -0400
Subject: [PATCH] Declare crypt, encrypt, and setkey per Posix

---
 newlib/libc/include/stdlib.h | 3 +++
 newlib/libc/include/sys/unistd.h | 6 ++
 2 files changed, 9 insertions(+)

diff --git a/newlib/libc/include/stdlib.h b/newlib/libc/include/stdlib.h
index 3194d6b..3d1b8a9 100644
--- a/newlib/libc/include/stdlib.h
+++ b/newlib/libc/include/stdlib.h
@@ -144,6 +144,9 @@ char *  _EXFUN(realpath, (const char *__restrict path, 
char *__restrict resolved_
 #if __BSD_VISIBLE
 int_EXFUN(rpmatch, (const char *response));
 #endif
+#if __XSI_VISIBLE
+_VOID  _EXFUN(setkey, (const char *__key));
+#endif
 _VOID  _EXFUN(srand,(unsigned __seed));
 double _EXFUN(strtod,(const char *__restrict __n, char **__restrict 
__end_PTR));
 double _EXFUN(_strtod_r,(struct _reent *,const char *__restrict __n, char 
**__restrict __end_PTR));
diff --git a/newlib/libc/include/sys/unistd.h b/newlib/libc/include/sys/unistd.h
index ef00575..05b4f9d 100644
--- a/newlib/libc/include/sys/unistd.h
+++ b/newlib/libc/include/sys/unistd.h
@@ -31,6 +31,9 @@ int _EXFUN(close, (int __fildes ));
 #if __POSIX_VISIBLE >= 199209
 size_t _EXFUN(confstr, (int __name, char *__buf, size_t __len));
 #endif
+#if __XSI_VISIBLE
+char *  _EXFUN(crypt, (const char *__key, const char *__salt));
+#endif
 #if __XSI_VISIBLE && __XSI_VISIBLE < 700
 char *  _EXFUN(ctermid, (char *__s ));
 #endif
@@ -46,6 +49,9 @@ int _EXFUN(dup2, (int __fildes, int __fildes2 ));
 int _EXFUN(dup3, (int __fildes, int __fildes2, int flags));
 int_EXFUN(eaccess, (const char *__path, int __mode));
 #endif
+#if __XSI_VISIBLE
+void   _EXFUN(encrypt, (char *__block, int __edflag));
+#endif
 #if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500)
 void   _EXFUN(endusershell, (void));
 #endif
-- 
2.8.3



Documentation patch: Clarify Cygwin's support for Win32 paths

2016-08-23 Thread Ken Brown

The attached patch is the one promised in

  https://www.cygwin.com/ml/cygwin/2016-08/msg00431.html

Ken
From e46d88d4141737f7f75ec1fb60b6e404f598a965 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Tue, 23 Aug 2016 13:24:49 -0400
Subject: [PATCH] Clarify Cygwin's support for Win32 paths

See https://www.cygwin.com/ml/cygwin/2016-08/msg00431.html.
---
 winsup/doc/pathnames.xml | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/winsup/doc/pathnames.xml b/winsup/doc/pathnames.xml
index 3c0bdc1..6f9fefa 100644
--- a/winsup/doc/pathnames.xml
+++ b/winsup/doc/pathnames.xml
@@ -6,15 +6,18 @@
 
 Introduction
 
-Cygwin supports both POSIX- and Win32-style paths.  Directory
+The Cygwin DLL supports both POSIX- and Win32-style paths.  Directory
 delimiters may be either forward slashes or backslashes.  Paths using
 backslashes or starting with a drive letter are always handled as
 Win32 paths.  POSIX paths must only use forward slashes as delimiter,
 otherwise they are treated as Win32 paths and file access might fail
 in surprising ways.
 
-The usage of Win32 paths, though possible, is deprecated,
-since it circumvents important internal path handling mechanisms. 
+Although the Cygwin DLL supports Win32 paths, not all
+Cygwin applications support them.  Moreover, the usage of Win32 paths
+circumvents important internal path handling mechanisms.  This usage
+is therefore strongly deprecated and may be removed in a future
+release of Cygwin.
 See  and
  for more information.
 
@@ -451,11 +454,12 @@ filesystem borders by commands like find 
-xdev.
 
 Using native Win32 paths
 
-Using native Win32 paths in Cygwin, while possible, is generally
+Using native Win32 paths in Cygwin, while often possible, is generally
 inadvisable.  Those paths circumvent all internal integrity checking and
 bypass the information given in the Cygwin mount table.
 
-The following paths are treated as native Win32 paths in Cygwin:
+The following paths are treated as native Win32 paths by the
+Cygwin DLL (but not necessarily by Cygwin applications):
 
 
   
-- 
2.8.3



Add _PC_CASE_INSENSITIVE flag to pathconf

2016-10-20 Thread Ken Brown

Patch attached.

I tested it by running getconf.exe, and also as follows:

$ cat case_sens_test.c
#include 
#include 

void
test (const char *path)
{
  int ret = pathconf (path, _PC_CASE_INSENSITIVE);
  printf ("pathconf (\"%s\", _PC_CASE_INSENSITIVE) returns %d\n", path, 
ret);

  if (ret == -1)
perror ("  pathconf");
}

int
main ()
{
  test ("/tmp");
  test ("/tmp/a");
  test ("/cygdrive/c/cygwin");
  test ("/");
  test (".");
}

$ gcc case_sens_test.c

$ ./a
pathconf ("/tmp", _PC_CASE_INSENSITIVE) returns 0
pathconf ("/tmp/a", _PC_CASE_INSENSITIVE) returns -1
  pathconf: No such file or directory
pathconf ("/cygdrive/c/cygwin", _PC_CASE_INSENSITIVE) returns 1
pathconf ("/", _PC_CASE_INSENSITIVE) returns 0
pathconf (".", _PC_CASE_INSENSITIVE) returns 0

This test was done, obviously, on a system with the obcaseinsensitive 
registry key set to 0, and with /tmp/a non-existent.  I also tested with 
the registry key set to 1, with the expected results.


Ken
From 04b507edbfbbaade6ef19ba9302ac9a758886995 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Thu, 20 Oct 2016 15:35:54 -0400
Subject: [PATCH] Add _PC_CASE_INSENSITIVE to [f]pathconf

Update the getconf utility to support the new flag as well as
_PC_POSIX_PERMISSIONS and _PC_POSIX_SECURITY.  These were previously
unsupported, probably as an oversight.
---
 newlib/libc/include/sys/unistd.h   | 1 +
 winsup/cygwin/fhandler.cc  | 2 ++
 winsup/cygwin/include/cygwin/version.h | 3 ++-
 winsup/cygwin/release/2.6.1| 2 ++
 winsup/utils/getconf.c | 3 +++
 5 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/newlib/libc/include/sys/unistd.h b/newlib/libc/include/sys/unistd.h
index 05b4f9d..143147d 100644
--- a/newlib/libc/include/sys/unistd.h
+++ b/newlib/libc/include/sys/unistd.h
@@ -490,6 +490,7 @@ int _EXFUN(unlinkat, (int, const char *, int));
 #define _PC_POSIX_PERMISSIONS90
 /* Ask for full POSIX permission support including uid/gid settings. */
 #define _PC_POSIX_SECURITY   91
+#define _PC_CASE_INSENSITIVE 92
 #endif
 
 /*
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index d77ccd3..9ab52ad 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1891,6 +1891,8 @@ fhandler_base::fpathconf (int v)
return pc.has_acls () || pc.fs_is_nfs ();
   set_errno (EINVAL);
   break;
+case _PC_CASE_INSENSITIVE:
+  return !!pc.objcaseinsensitive ();
 default:
   set_errno (EINVAL);
   break;
diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index 1c1402c..6ba602e 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -469,12 +469,13 @@ details. */
   302: Export nl_langinfo_l.
   303: Export pthread_getname_np, pthread_setname_np.
   304: Export strerror_l, strptime_l, wcsftime_l.
+  305: [f]pathconf flag _PC_CASE_INSENSITIVE added.
 
   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 304
+#define CYGWIN_VERSION_API_MINOR 305
 
 /* 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/release/2.6.1 b/winsup/cygwin/release/2.6.1
index 61ce2de..7ced3c4 100644
--- a/winsup/cygwin/release/2.6.1
+++ b/winsup/cygwin/release/2.6.1
@@ -1,6 +1,8 @@
 What's new:
 ---
 
+- Add _PC_CASE_INSENSITIVE flag to [f]pathconf(3).
+
 
 What changed:
 -
diff --git a/winsup/utils/getconf.c b/winsup/utils/getconf.c
index 8539233..e6b319e 100644
--- a/winsup/utils/getconf.c
+++ b/winsup/utils/getconf.c
@@ -186,6 +186,7 @@ static const struct conf_variable conf_table[] =
   { "POSIX2_RE_DUP_MAX",   CONSTANT,   _POSIX2_RE_DUP_MAX  
},
 
   /* Variables from fpathconf() */
+  { "CASE_INSENSITIVE",PATHCONF,   
_PC_CASE_INSENSITIVE},
   { "FILESIZEBITS",PATHCONF,   _PC_FILESIZEBITS
},
   { "LINK_MAX",PATHCONF,   _PC_LINK_MAX
},
   { "MAX_CANON",   PATHCONF,   _PC_MAX_CANON   
},
@@ -195,10 +196,12 @@ static const struct conf_variable conf_table[] =
   { "PIPE_BUF",PATHCONF,   _PC_PIPE_BUF
},
   { "POSIX2_SYMLINKS", PATHCONF,   _PC_2_SYMLINKS  
},
   { "POSIX_ALLOC_SIZE_MIN",PATHCONF,   _PC_ALLOC_SIZE_MIN  
},
+  { "POSIX_PERMISSIONS",   PATHCONF,   _PC_POSIX_PERMISSIONS   
},

Define sigsetjmp/siglongjmp only if __POSIX_VISIBLE

2017-08-06 Thread Ken Brown

The attached patch fixes the issue reported here:

  https://cygwin.com/ml/cygwin/2017-08/msg00060.html

I'm not sure if I was correct in including RTEMS or if this should have 
been Cygwin only.  If the former, I probably should have sent this to 
the Newlib list.


Ken
From 45060307b1e8e06a522cd95e9567155e98dda832 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Sun, 6 Aug 2017 17:40:43 -0400
Subject: [PATCH] Define sigsetjmp/siglongjmp only if __POSIX_VISIBLE

---
 newlib/libc/include/machine/setjmp.h | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/newlib/libc/include/machine/setjmp.h 
b/newlib/libc/include/machine/setjmp.h
index 2b4dd8b91..fc5639f3d 100644
--- a/newlib/libc/include/machine/setjmp.h
+++ b/newlib/libc/include/machine/setjmp.h
@@ -368,7 +368,7 @@ typedef int jmp_buf[_JBLEN];
 
 _END_STD_C
 
-#if defined(__CYGWIN__) || defined(__rtems__)
+#if (defined(__CYGWIN__) || defined(__rtems__)) && __POSIX_VISIBLE
 #include 
 
 #ifdef __cplusplus
@@ -376,6 +376,8 @@ extern "C" {
 #endif
 
 /* POSIX sigsetjmp/siglongjmp macros */
+
+
 #ifdef _JBTYPE
 typedef _JBTYPE sigjmp_buf[_JBLEN+1+((sizeof (_JBTYPE) + sizeof (sigset_t) - 1)
 /sizeof (_JBTYPE))];
@@ -450,4 +452,4 @@ extern int _setjmp (jmp_buf);
 #ifdef __cplusplus
 }
 #endif
-#endif /* __CYGWIN__ or __rtems__ */
+#endif /* (__CYGWIN__ or __rtems__) and __POSIX_VISIBLE */
-- 
2.13.2



Re: Define sigsetjmp/siglongjmp only if __POSIX_VISIBLE

2017-08-06 Thread Ken Brown

On 8/6/2017 5:46 PM, Ken Brown wrote:

The attached patch fixes the issue reported here:

   https://cygwin.com/ml/cygwin/2017-08/msg00060.html

I'm not sure if I was correct in including RTEMS or if this should have 
been Cygwin only.  If the former, I probably should have sent this to 
the Newlib list.


Sorry, I accidentally made a whitespace change.  Corrected patch attached.

Ken
From 50cceaf0e1d33ddf3fc62399bc15761af93fa29d Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Sun, 6 Aug 2017 17:40:43 -0400
Subject: [PATCH] Define sigsetjmp/siglongjmp only if __POSIX_VISIBLE

---
 newlib/libc/include/machine/setjmp.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/newlib/libc/include/machine/setjmp.h 
b/newlib/libc/include/machine/setjmp.h
index 2b4dd8b91..e6c3142ed 100644
--- a/newlib/libc/include/machine/setjmp.h
+++ b/newlib/libc/include/machine/setjmp.h
@@ -368,7 +368,7 @@ typedef int jmp_buf[_JBLEN];
 
 _END_STD_C
 
-#if defined(__CYGWIN__) || defined(__rtems__)
+#if (defined(__CYGWIN__) || defined(__rtems__)) && __POSIX_VISIBLE
 #include 
 
 #ifdef __cplusplus
@@ -450,4 +450,4 @@ extern int _setjmp (jmp_buf);
 #ifdef __cplusplus
 }
 #endif
-#endif /* __CYGWIN__ or __rtems__ */
+#endif /* (__CYGWIN__ or __rtems__) and __POSIX_VISIBLE */
-- 
2.13.2



renameat2

2017-08-18 Thread Ken Brown

Linux has a system call 'renameat2' which is like renameat but has an extra 
'flags' argument.  In particular, one can pass the RENAME_NOREPLACE flag to 
cause the rename to fail with EEXIST if the target of the rename exists.  See

 http://man7.org/linux/man-pages/man2/rename.2.html

macOS has a similar functionality, provided by the function 'renameatx_np' with 
the flag RENAME_EXCL.

There's also a recently introduced Gnulib module 'renameat2', but it requires 
two system calls on Cygwin (one to test existence and the second to do the 
rename), so that there is a race condition.  On Linux and macOS it uses 
renameat2 and renameatx_np to avoid the race.

The attached patch implements renameat2 on Cygwin (but only supporting the 
RENAME_NOREPLACE flag).  I've written it so that a rename that just changes 
case on a case-insensitive file system succeeds.

If the patch is accepted, I'll submit a second patch that documents the new 
function.

Here's a simple test program:

$ cat rename_noreplace.c
#include 
#include 
#include 

int
main ()
{
 int res = renameat2 (AT_FDCWD, "foo", AT_FDCWD, "bar", RENAME_NOREPLACE);
 if (res < 0)
   perror ("renameat2");
}

$ gcc -o rename_noreplace rename_noreplace.c

$ touch foo bar

$ ./rename_noreplace.exe
renameat2: File exists

$ ls foo bar
bar  foo

$ rm bar

$ ./rename_noreplace.exe

$ ls foo bar
ls: cannot access 'foo': No such file or directory
bar

Ken
From 23edb25c9c0b6a21aefb10372db945807b2b8e3f Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Thu, 17 Aug 2017 09:12:15 -0400
Subject: [PATCH] cygwin: Implement renameat2

Define the RENAME_* flags in  as defined on Linux in
, but support only RENAME_NOREPLACE.
---
 newlib/libc/include/stdio.h|  3 +++
 winsup/cygwin/common.din   |  1 +
 winsup/cygwin/include/cygwin/fs.h  |  5 +
 winsup/cygwin/include/cygwin/version.h |  4 +++-
 winsup/cygwin/syscalls.cc  | 41 +-
 5 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/newlib/libc/include/stdio.h b/newlib/libc/include/stdio.h
index 5d8cb1092..331a1cf07 100644
--- a/newlib/libc/include/stdio.h
+++ b/newlib/libc/include/stdio.h
@@ -384,6 +384,9 @@ int _EXFUN(vdprintf, (int, const char *__restrict, __VALIST)
 #endif
 #if __ATFILE_VISIBLE
 int_EXFUN(renameat, (int, const char *, int, const char *));
+# ifdef __CYGWIN__
+int_EXFUN(renameat2, (int, const char *, int, const char *, unsigned int));
+# endif
 #endif
 
 /*
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index 8da432b8a..ca6ff3cf9 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -1168,6 +1168,7 @@ remquof NOSIGFE
 remquol NOSIGFE
 rename SIGFE
 renameat SIGFE
+renameat2 SIGFE
 res_close = __res_close SIGFE
 res_init = __res_init SIGFE
 res_mkquery = __res_mkquery SIGFE
diff --git a/winsup/cygwin/include/cygwin/fs.h 
b/winsup/cygwin/include/cygwin/fs.h
index f606ffc39..14454376f 100644
--- a/winsup/cygwin/include/cygwin/fs.h
+++ b/winsup/cygwin/include/cygwin/fs.h
@@ -19,4 +19,9 @@ details. */
 #define BLKPBSZGET   0x127b
 #define BLKGETSIZE64 0x00041268
 
+/* Flags for renameat2, from /usr/include/linux/fs.h. */
+#define RENAME_NOREPLACE (1 << 0)
+#define RENAME_EXCHANGE  (1 << 1)
+#define RENAME_WHITEOUT  (1 << 2)
+
 #endif
diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index efd4ac017..7640abfad 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -481,12 +481,14 @@ details. */
   314: Export explicit_bzero.
   315: Export pthread_mutex_timedlock.
   316: Export pthread_rwlock_timedrdlock, pthread_rwlock_timedwrlock.
+  317: Export renameat2.  Add RENAME_NOREPLACE, RENAME_EXCHANGE,
+   RENAME_WHITEOUT.
 
   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 316
+#define CYGWIN_VERSION_API_MINOR 317
 
 /* 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/syscalls.cc b/winsup/cygwin/syscalls.cc
index 885931632..d756f5f35 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -60,6 +60,7 @@ details. */
 #include "tls_pbuf.h"
 #include "sync.h"
 #include "child_info.h"
+#include   /* needed for RENAME_NOREPLACE */
 
 #undef _close
 #undef _lseek
@@ -2048,8 +2049,12 @@ nt_path_has_executable_suffix (PUNICODE_STRING upath)
   return false;
 }
 
-extern "C" int
-rename (const char *oldpath, const char *newpath)
+/* If newpath names an existing file and the RENAME_NOREPLACE flag is
+   specified, fail with EEXIST.  Exception: Don't fail if the pu

Re: renameat2

2017-08-18 Thread Ken Brown

On 8/18/2017 10:33 AM, Eric Blake wrote:

Please only define RENAME_NOREPLACE for now; that way, software can
probe what is defined to know what will work (defining a flag that will
always be an error is not as useful as leaving it undefined - and while
we may add RENAME_EXCHANGE support, I don't see how we can ever do
RENAME_WHITEOUT).


Thanks for the feedback.  Revised patch attached.

From 136b0dfd53e147002e134048658d20f452402c9f Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Thu, 17 Aug 2017 09:12:15 -0400
Subject: [PATCH] cygwin: Implement renameat2

Define the RENAME_NOREPLACE flag in  as defined on Linux
in .  The other RENAME_* flags defined on Linux are not
supported.
---
 newlib/libc/include/stdio.h|  3 +++
 winsup/cygwin/common.din   |  1 +
 winsup/cygwin/include/cygwin/fs.h  |  6 +
 winsup/cygwin/include/cygwin/version.h |  3 ++-
 winsup/cygwin/syscalls.cc  | 41 +-
 5 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/newlib/libc/include/stdio.h b/newlib/libc/include/stdio.h
index 5d8cb1092..331a1cf07 100644
--- a/newlib/libc/include/stdio.h
+++ b/newlib/libc/include/stdio.h
@@ -384,6 +384,9 @@ int _EXFUN(vdprintf, (int, const char *__restrict, __VALIST)
 #endif
 #if __ATFILE_VISIBLE
 int_EXFUN(renameat, (int, const char *, int, const char *));
+# ifdef __CYGWIN__
+int_EXFUN(renameat2, (int, const char *, int, const char *, unsigned int));
+# endif
 #endif
 
 /*
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index 8da432b8a..ca6ff3cf9 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -1168,6 +1168,7 @@ remquof NOSIGFE
 remquol NOSIGFE
 rename SIGFE
 renameat SIGFE
+renameat2 SIGFE
 res_close = __res_close SIGFE
 res_init = __res_init SIGFE
 res_mkquery = __res_mkquery SIGFE
diff --git a/winsup/cygwin/include/cygwin/fs.h 
b/winsup/cygwin/include/cygwin/fs.h
index f606ffc39..48b0cca45 100644
--- a/winsup/cygwin/include/cygwin/fs.h
+++ b/winsup/cygwin/include/cygwin/fs.h
@@ -19,4 +19,10 @@ details. */
 #define BLKPBSZGET   0x127b
 #define BLKGETSIZE64 0x00041268
 
+/* Flags for renameat2, from /usr/include/linux/fs.h.  For now we
+   support only RENAME_NOREPLACE. */
+#define RENAME_NOREPLACE (1 << 0)
+/* #define RENAME_EXCHANGE  (1 << 1) */
+/* #define RENAME_WHITEOUT  (1 << 2) */
+
 #endif
diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index efd4ac017..0384f77da 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -481,12 +481,13 @@ details. */
   314: Export explicit_bzero.
   315: Export pthread_mutex_timedlock.
   316: Export pthread_rwlock_timedrdlock, pthread_rwlock_timedwrlock.
+  317: Export renameat2.  Add RENAME_NOREPLACE.
 
   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 316
+#define CYGWIN_VERSION_API_MINOR 317
 
 /* 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/syscalls.cc b/winsup/cygwin/syscalls.cc
index 885931632..d756f5f35 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -60,6 +60,7 @@ details. */
 #include "tls_pbuf.h"
 #include "sync.h"
 #include "child_info.h"
+#include   /* needed for RENAME_NOREPLACE */
 
 #undef _close
 #undef _lseek
@@ -2048,8 +2049,12 @@ nt_path_has_executable_suffix (PUNICODE_STRING upath)
   return false;
 }
 
-extern "C" int
-rename (const char *oldpath, const char *newpath)
+/* If newpath names an existing file and the RENAME_NOREPLACE flag is
+   specified, fail with EEXIST.  Exception: Don't fail if the purpose
+   of the rename is just to change the case of oldpath on a
+   case-insensitive file system. */
+static int
+rename2 (const char *oldpath, const char *newpath, unsigned int flags)
 {
   tmp_pathbuf tp;
   int res = -1;
@@ -2068,6 +2073,12 @@ rename (const char *oldpath, const char *newpath)
 
   __try
 {
+  if (flags & ~RENAME_NOREPLACE)
+   /* RENAME_NOREPLACE is the only flag currently supported. */
+   {
+ set_errno (ENOTSUP);
+ __leave;
+   }
   if (!*oldpath || !*newpath)
{
  /* Reject rename("","x"), rename("x","").  */
@@ -2337,6 +2348,13 @@ rename (const char *oldpath, const char *newpath)
  __leave;
}
 
+  /* Should we replace an existing file? */
+  if ((removepc || dstpc->exists ()) && (flags & RENAME_NOREPLACE))
+   {
+ set_errno (EEXIST);
+ __leave;
+   }
+
   /* Opening the file must be part of the transaction.  It's not sufficient
 to call only NtSetInformationF

Re: renameat2

2017-08-18 Thread Ken Brown

Hi Corinna,

On 8/18/2017 11:15 AM, Corinna Vinschen wrote:

Hi Ken,

On Aug 18 09:21, Ken Brown wrote:

Linux has a system call 'renameat2' which is like renameat but has an
extra 'flags' argument.  In particular, one can pass the
RENAME_NOREPLACE flag to cause the rename to fail with EEXIST if the
target of the rename exists.  See

  http://man7.org/linux/man-pages/man2/rename.2.html

macOS has a similar functionality, provided by the function
'renameatx_np' with the flag RENAME_EXCL.

There's also a recently introduced Gnulib module 'renameat2', but it
requires two system calls on Cygwin (one to test existence and the
second to do the rename), so that there is a race condition.  On Linux
and macOS it uses renameat2 and renameatx_np to avoid the race.

The attached patch implements renameat2 on Cygwin (but only supporting
the RENAME_NOREPLACE flag).  I've written it so that a rename that
just changes case on a case-insensitive file system succeeds.

If the patch is accepted, I'll submit a second patch that documents
the new function.


Neat stuff, but there are a few points for discussion, see below.


--- a/winsup/cygwin/include/cygwin/fs.h
+++ b/winsup/cygwin/include/cygwin/fs.h
@@ -19,4 +19,9 @@ details. */
  #define BLKPBSZGET   0x127b
  #define BLKGETSIZE64 0x00041268
  
+/* Flags for renameat2, from /usr/include/linux/fs.h. */

+#define RENAME_NOREPLACE (1 << 0)
+#define RENAME_EXCHANGE  (1 << 1)
+#define RENAME_WHITEOUT  (1 << 2)


Given that there's no standard for this call (yet), do we really want to
expose flag values we don't support?  I would opt for only RENAME_NOREPLACE
for now and skip the others.


+
  #endif
diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index efd4ac017..7640abfad 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -481,12 +481,14 @@ details. */
314: Export explicit_bzero.
315: Export pthread_mutex_timedlock.
316: Export pthread_rwlock_timedrdlock, pthread_rwlock_timedwrlock.
+  317: Export renameat2.  Add RENAME_NOREPLACE, RENAME_EXCHANGE,
+   RENAME_WHITEOUT.


You can drop the flag values here.  renameat2 is sufficient.


+rename2 (const char *oldpath, const char *newpath, unsigned int flags)
  {
tmp_pathbuf tp;
int res = -1;
@@ -2068,6 +2073,12 @@ rename (const char *oldpath, const char *newpath)
  
__try

  {
+  if (flags & ~RENAME_NOREPLACE)
+   /* RENAME_NOREPLACE is the only flag currently supported. */
+   {
+ set_errno (ENOTSUP);


That should ideally be EINVAL.  Unsupported bit values in a flag argument?
EINVAL, please.


+ __leave;
+   }
if (!*oldpath || !*newpath)
{
  /* Reject rename("","x"), rename("x","").  */
@@ -2337,6 +2348,13 @@ rename (const char *oldpath, const char *newpath)
  __leave;
}
  
+  /* Should we replace an existing file? */

+  if ((removepc || dstpc->exists ()) && (flags & RENAME_NOREPLACE))
+   {
+ set_errno (EEXIST);
+ __leave;
+   }
+


Do we really need this test here?  If you check at this point and then
go ahead preparing the actual rename operation, you have the atomicity
problem again which renameat2 is trying to solve.

But there's light.  NtSetInformationFile(FileRenameInformation) already
supports RENAME_NOREPLACE :)

Have a look at line 2494 (prior to your patch):

 pfri->ReplaceIfExists = TRUE;

if you replace this with something like

 pfri->ReplaceIfExists = !(flags & RENAME_NOREPLACE);

it should give us the atomic behaviour of renameat2 on Linux.

Another upside is, the status code returned is STATUS_OBJECT_NAME_COLLISION,
which translates to Win32 error ERROR_ALREADY_EXISTS, which in turn is
already converted to EEXIST by Cygwin, so there's nothing more to do :)

What do you think?


Thanks for the improvements!  A revised patch is attached.  As you'll 
see, I still found a few places where I thought I needed to explicitly 
set the errno to EEXIST.  Let me know if any of these could be avoided.


Thanks.

Ken
From d5798b371ceabfe6a7912472edd32da1ebd7dcb7 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Thu, 17 Aug 2017 09:12:15 -0400
Subject: [PATCH] cygwin: Implement renameat2

Define the RENAME_NOREPLACE flag in  as defined on Linux
in .  The other RENAME_* flags defined on Linux are not
supported.
---
 newlib/libc/include/stdio.h|  3 ++
 winsup/cygwin/common.din   |  1 +
 winsup/cygwin/include/cygwin/fs.h  |  6 +++
 winsup/cygwin/include/cygwin/version.h |  3 +-
 winsup/cygwin/syscalls.cc  | 67 +++---
 5 files changed, 73 insertions(+), 7 deletions(-)

diff --git a/newlib/libc/include/stdio.h b/newlib/libc/include/stdio.h
index 5d8cb1092..331a1c

Re: renameat2

2017-08-19 Thread Ken Brown

Hi Corinna,

On 8/19/2017 5:57 AM, Corinna Vinschen wrote:

Hi Ken,

On Aug 18 18:24, Ken Brown wrote:
Thanks for the improvements!  A revised patch is attached.  As you'll see, I

still found a few places where I thought I needed to explicitly set the
errno to EEXIST.  Let me know if any of these could be avoided.


No, you're right.  Just one thing:


@@ -2410,6 +2433,11 @@ rename (const char *oldpath, const char *newpath)
 unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */
if (dstpc->isdir ())
{
+ if (noreplace)
+   {
+ set_errno (EEXIST);
+ __leave;
+   }
  status = unlink_nt (*dstpc);
  if (!NT_SUCCESS (status))
{
@@ -2423,6 +2451,11 @@ rename (const char *oldpath, const char *newpath)
 due to a mangled suffix. */
else if (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY))
{
+ if (noreplace)
+   {
+ set_errno (EEXIST);
+ __leave;
+   }
  status = NtOpenFile (&nfh, FILE_WRITE_ATTRIBUTES,
   dstpc->get_object_attr (attr, sec_none_nih),
   &io, FILE_SHARE_VALID_FLAGS,


Both of the above cases are just border cases of one and the same
problem, the destination file already exists.

In retrospect your original patch was more concise:

+  /* Should we replace an existing file? */
+  if ((removepc || dstpc->exists ()) && (flags & RENAME_NOREPLACE))
+   {
+ set_errno (EEXIST);
+ __leave;
+   }

The atomicity considerations are not affected by this test anyway, but
it would avoid starting and stopping a transaction on NTFS for no good
reason.

Maybe it's better to revert to this test and drop the other two again?


@@ -2491,11 +2524,15 @@ rename (const char *oldpath, const char *newpath)
  __leave;
}
pfri = (PFILE_RENAME_INFORMATION) tp.w_get ();
-  pfri->ReplaceIfExists = TRUE;
+  pfri->ReplaceIfExists = !noreplace;
pfri->RootDirectory = NULL;
pfri->FileNameLength = dstpc->get_nt_native_path ()->Length;
memcpy (&pfri->FileName,  dstpc->get_nt_native_path ()->Buffer,
  pfri->FileNameLength);
+  /* If dstpc points to an existing file and RENAME_NOREPLACE has
+been specified, then we should get NT error
+STATUS_OBJECT_NAME_COLLISION ==> Win32 error
+ERROR_ALREADY_EXISTS ==> Cygwin error EEXIST. */
status = NtSetInformationFile (fh, &io, pfri,
 sizeof *pfri + pfri->FileNameLength,
 FileRenameInformation);
@@ -2509,6 +2546,11 @@ rename (const char *oldpath, const char *newpath)
if (status == STATUS_ACCESS_DENIED && dstpc->exists ()
  && !dstpc->isdir ())
{
+ if (noremove)
+   {
+ set_errno (EEXIST);
+ __leave;
+   }


Oh, right, that's a good catch.

The patch is ok as is, just let me know what you think of the above
minor tweak (and send the revised patch if you agree).


Yes, I agree.  But can't I also drop the third test (where you said 
"good catch") for the same reason?  I've done that in the attached.  If 
I'm wrong and I still need that third test, let me know and I'll put it 
back.


Thanks.

Ken
From bbff16b727172a459a9a052b0b948641c82d80eb Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Thu, 17 Aug 2017 09:12:15 -0400
Subject: [PATCH] cygwin: Implement renameat2

Define the RENAME_NOREPLACE flag in  as defined on Linux
in .  The other RENAME_* flags defined on Linux are not
supported.
---
 newlib/libc/include/stdio.h|  3 +++
 winsup/cygwin/common.din   |  1 +
 winsup/cygwin/include/cygwin/fs.h  |  6 +
 winsup/cygwin/include/cygwin/version.h |  3 ++-
 winsup/cygwin/syscalls.cc  | 48 +-
 5 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/newlib/libc/include/stdio.h b/newlib/libc/include/stdio.h
index 5d8cb1092..331a1cf07 100644
--- a/newlib/libc/include/stdio.h
+++ b/newlib/libc/include/stdio.h
@@ -384,6 +384,9 @@ int _EXFUN(vdprintf, (int, const char *__restrict, __VALIST)
 #endif
 #if __ATFILE_VISIBLE
 int_EXFUN(renameat, (int, const char *, int, const char *));
+# ifdef __CYGWIN__
+int_EXFUN(renameat2, (int, const char *, int, const char *, unsigned int));
+# endif
 #endif
 
 /*
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index 8da432b8a..ca6ff3cf9 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -1168,6 +1168,7 @@ remquof NOSIGFE
 remquol NOSIGFE
 rename SIGFE
 renameat SIGFE
+renameat2 SIGFE
 res_close = __res_close SIGFE
 res_init = __res_init SIGFE
 res_mkquery = __res_mkquery SIGF

Re: renameat2

2017-08-19 Thread Ken Brown
On 8/19/2017 12:37 PM, Corinna Vinschen wrote:
> Oh, one more thing.  This is a question to Yaakov, too.
> 
> diff --git a/newlib/libc/include/stdio.h b/newlib/libc/include/stdio.h
> index 5d8cb1092..331a1cf07 100644
> --- a/newlib/libc/include/stdio.h
> +++ b/newlib/libc/include/stdio.h
> @@ -384,6 +384,9 @@ int _EXFUN(vdprintf, (int, const char *__restrict, 
> __VALIST)
>   #endif
>   #if __ATFILE_VISIBLE
>   int_EXFUN(renameat, (int, const char *, int, const char *));
> +# ifdef __CYGWIN__
> +int_EXFUN(renameat2, (int, const char *, int, const char *, unsigned 
> int));
> +# endif
>   #endif
> 
> Does it makes sense to guard the renameat2 prototype more extensively
> to cater for standards junkies?  __MISC_VISIBLE, perhaps?

I'll defer to Yaakov.  But here's a related question.  Is renameat
currently guarded properly?  The Linux man page says:

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

   renameat():
   Since glibc 2.10:
   _POSIX_C_SOURCE >= 200809L
   Before glibc 2.10:
   _ATFILE_SOURCE

This suggests that we should do something like the following:

diff --git a/newlib/libc/include/stdio.h b/newlib/libc/include/stdio.h
index 331a1cf07..9eb0964f2 100644
--- a/newlib/libc/include/stdio.h
+++ b/newlib/libc/include/stdio.h
@@ -381,8 +381,6 @@ FILE *  _EXFUN(open_memstream, (char **, size_t *));
 int_EXFUN(vdprintf, (int, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0;
 # endif
-#endif
-#if __ATFILE_VISIBLE
 int_EXFUN(renameat, (int, const char *, int, const char *));
 # ifdef __CYGWIN__
 int_EXFUN(renameat2, (int, const char *, int, const char *, unsigned int));

Ken


Re: renameat2

2017-08-19 Thread Ken Brown

On 8/19/2017 12:28 PM, Corinna Vinschen wrote:

Doc changes coming? :)


Attached.

Ken

From 0704541f1d29e0d9aa0af6e549f8ca0114a44a7c Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Sat, 19 Aug 2017 13:15:04 -0400
Subject: [PATCH] Document renameat2

---
 winsup/cygwin/release/2.9.0 | 2 ++
 winsup/doc/new-features.xml | 4 
 winsup/doc/posix.xml| 4 
 3 files changed, 10 insertions(+)

diff --git a/winsup/cygwin/release/2.9.0 b/winsup/cygwin/release/2.9.0
index 421d6f24f..ac4c64949 100644
--- a/winsup/cygwin/release/2.9.0
+++ b/winsup/cygwin/release/2.9.0
@@ -6,6 +6,8 @@ What's new:
 - New APIs: pthread_mutex_timedwait, pthread_rwlock_timedrdlock,
pthread_rwlock_timedwrlock.
 
+- New API: renameat2.
+
 
 What changed:
 -
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index 23673d1e0..0aa857730 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -17,6 +17,10 @@ New APIs: pthread_mutex_timedwait, 
pthread_rwlock_timedrdlock,
 pthread_rwlock_timedwrlock.
 
 
+
+New API: renameat2.
+
+
 
 Improved implementation of <elf.h>.
 
diff --git a/winsup/doc/posix.xml b/winsup/doc/posix.xml
index a2fffeebf..6e96272b7 100644
--- a/winsup/doc/posix.xml
+++ b/winsup/doc/posix.xml
@@ -1356,6 +1356,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).
 ptsname_r
 putwc_unlocked
 putwchar_unlocked
+renameat2  (see chapter "Implementation Notes")
 qsort_r(see chapter "Implementation Notes")
 quotactl
 rawmemchr
@@ -1671,6 +1672,9 @@ group quotas, no inode quotas, no time constraints.
 qsort_r is available in both BSD and GNU flavors,
 depending on whether _BSD_SOURCE or _GNU_SOURCE is defined when 
compiling.
 
+The Linux-specific function renameat2 only
+supports the RENAME_NOREPLACE flag.
+
 basename is available in both POSIX and GNU flavors,
 depending on whether libgen.h is included or not.
 
-- 
2.14.1



[PATCH 03/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::root

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/fhandler_process.cc | 2 +-
 winsup/cygwin/pinfo.cc| 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/fhandler_process.cc 
b/winsup/cygwin/fhandler_process.cc
index 97436dd1b..08cc7ea92 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -478,7 +478,7 @@ format_process_root (void *data, char *&destbuf)
   cfree (destbuf);
   destbuf = NULL;
 }
-  destbuf = p->root (fs);
+  destbuf = p ? p->root (fs) : NULL;
   if (!destbuf || !*destbuf)
 {
   destbuf = cstrdup ("");
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index bba9ee494..9fe1b3a88 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -884,7 +884,7 @@ char *
 _pinfo::root (size_t& n)
 {
   char *s;
-  if (!this || !pid)
+  if (!pid)
 return NULL;
   if (pid != myself->pid && !ISSTATE (this, PID_NOTCYGWIN))
 {
-- 
2.14.1



[PATCH 11/12] cygwin: Remove comparison of 'this' to NULL in _pinfo::exists

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/fhandler_termios.cc |  2 +-
 winsup/cygwin/pinfo.cc|  2 +-
 winsup/cygwin/signal.cc   |  2 +-
 winsup/cygwin/sigproc.cc  |  5 +++--
 winsup/cygwin/times.cc| 10 +++---
 5 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/winsup/cygwin/fhandler_termios.cc 
b/winsup/cygwin/fhandler_termios.cc
index 19fcfc9cd..4ce53433a 100644
--- a/winsup/cygwin/fhandler_termios.cc
+++ b/winsup/cygwin/fhandler_termios.cc
@@ -131,7 +131,7 @@ tty_min::kill_pgrp (int sig)
   for (unsigned i = 0; i < pids.npids; i++)
 {
   _pinfo *p = pids[i];
-  if (!p->exists () || p->ctty != ntty || p->pgid != pgid)
+  if (!p || !p->exists () || p->ctty != ntty || p->pgid != pgid)
continue;
   if (p == myself)
killself = sig != __SIGSETPGRP && !exit_state;
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 7193f6884..e4eef8b3c 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -529,7 +529,7 @@ _pinfo::set_ctty (fhandler_termios *fh, int flags)
 bool __reg1
 _pinfo::exists ()
 {
-  return this && process_state && !(process_state & (PID_EXITED | PID_REAPED | 
PID_EXECED));
+  return process_state && !(process_state & (PID_EXITED | PID_REAPED | 
PID_EXECED));
 }
 
 bool
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
index 016fce1de..69c5e2aad 100644
--- a/winsup/cygwin/signal.cc
+++ b/winsup/cygwin/signal.cc
@@ -332,7 +332,7 @@ kill_pgrp (pid_t pid, siginfo_t& si)
 {
   _pinfo *p = pids[i];
 
-  if (!p->exists ())
+  if (!p || !p->exists ())
continue;
 
   /* Is it a process we want to kill?  */
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index 36fc64903..92fa5ea3d 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -152,7 +152,8 @@ proc_can_be_signalled (_pinfo *p)
 bool __reg1
 pid_exists (pid_t pid)
 {
-  return pinfo (pid)->exists ();
+  pinfo p (pid);
+  return p && p->exists ();
 }
 
 /* Return true if this is one of our children, false otherwise.  */
@@ -1135,7 +1136,7 @@ remove_proc (int ci)
   if (_my_tls._ctinfo != procs[ci].wait_thread)
procs[ci].wait_thread->terminate_thread ();
 }
-  else if (procs[ci]->exists ())
+  else if (procs[ci] && procs[ci]->exists ())
 return true;
 
   sigproc_printf ("removing procs[%d], pid %d, nprocs %d", ci, procs[ci]->pid,
diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc
index fb480513f..5da0bbc7a 100644
--- a/winsup/cygwin/times.cc
+++ b/winsup/cygwin/times.cc
@@ -522,7 +522,7 @@ clock_gettime (clockid_t clk_id, struct timespec *tp)
pid = getpid ();
 
   pinfo p (pid);
-  if (!p->exists ())
+  if (!p || !p->exists ())
{
  set_errno (EINVAL);
  return -1;
@@ -746,8 +746,12 @@ clock_setres (clockid_t clk_id, struct timespec *tp)
 extern "C" int
 clock_getcpuclockid (pid_t pid, clockid_t *clk_id)
 {
-  if (pid != 0 && !pinfo (pid)->exists ())
-return (ESRCH);
+  if (pid != 0)
+{
+  pinfo p (pid);
+  if (!p || !p->exists ())
+   return (ESRCH);
+}
   *clk_id = (clockid_t) PID_TO_CLOCKID (pid);
   return 0;
 }
-- 
2.14.1



[PATCH 02/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::fds

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/fhandler_process.cc | 2 +-
 winsup/cygwin/pinfo.cc| 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/fhandler_process.cc 
b/winsup/cygwin/fhandler_process.cc
index bbb44fa56..97436dd1b 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -375,7 +375,7 @@ format_process_fd (void *data, char *&destbuf)
 {
   if (destbuf)
cfree (destbuf);
-  destbuf = p->fds (fs);
+  destbuf = p ? p->fds (fs) : NULL;
   *((process_fd_t *) data)->fd_type = virt_symlink;
 }
   else
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index a504828fe..bba9ee494 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -856,7 +856,7 @@ char *
 _pinfo::fds (size_t &n)
 {
   char *s;
-  if (!this || !pid)
+  if (!pid)
 return NULL;
   if (pid != myself->pid)
 {
-- 
2.14.1



[PATCH 01/12] cygwin: Remove comparisons of 'this' to 'NULL' in fhandler_dsp.cc

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/fhandler_dsp.cc | 55 +++
 1 file changed, 40 insertions(+), 15 deletions(-)

diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc
index 5ae3309f8..b5c685bf8 100644
--- a/winsup/cygwin/fhandler_dsp.cc
+++ b/winsup/cygwin/fhandler_dsp.cc
@@ -63,7 +63,7 @@ class fhandler_dev_dsp::Audio
   void convert_S16LE_S16BE (unsigned char *buffer, int size_bytes);
   void fillFormat (WAVEFORMATEX * format,
   int rate, int bits, int channels);
-  unsigned blockSize (int rate, int bits, int channels);
+  static unsigned blockSize (int rate, int bits, int channels);
   void (fhandler_dev_dsp::Audio::*convert_)
 (unsigned char *buffer, int size_bytes);
 
@@ -115,6 +115,7 @@ class fhandler_dev_dsp::Audio_out: public Audio
   void stop (bool immediately = false);
   int write (const char *pSampleData, int nBytes);
   void buf_info (audio_buf_info *p, int rate, int bits, int channels);
+  static void default_buf_info (audio_buf_info *p, int rate, int bits, int 
channels);
   void callback_sampledone (WAVEHDR *pHdr);
   bool parsewav (const char *&pData, int &nBytes,
 int rate, int bits, int channels);
@@ -149,6 +150,7 @@ public:
   void stop ();
   bool read (char *pSampleData, int &nBytes);
   void buf_info (audio_buf_info *p, int rate, int bits, int channels);
+  static void default_buf_info (audio_buf_info *p, int rate, int bits, int 
channels);
   void callback_blockfull (WAVEHDR *pHdr);
 
 private:
@@ -499,11 +501,11 @@ void
 fhandler_dev_dsp::Audio_out::buf_info (audio_buf_info *p,
   int rate, int bits, int channels)
 {
-  p->fragstotal = MAX_BLOCKS;
-  if (this && dev_)
+  if (dev_)
 {
   /* If the device is running we use the internal values,
 possibly set from the wave file. */
+  p->fragstotal = MAX_BLOCKS;
   p->fragsize = blockSize (freq_, bits_, channels_);
   p->fragments = Qisr2app_->query ();
   if (pHdr_ != NULL)
@@ -514,10 +516,17 @@ fhandler_dev_dsp::Audio_out::buf_info (audio_buf_info *p,
 }
   else
 {
+  default_buf_info(p, rate, bits, channels);
+}
+}
+
+void fhandler_dev_dsp::Audio_out::default_buf_info (audio_buf_info *p,
+int rate, int bits, int 
channels)
+{
+  p->fragstotal = MAX_BLOCKS;
   p->fragsize = blockSize (rate, bits, channels);
   p->fragments = MAX_BLOCKS;
   p->bytes = p->fragsize * p->fragments;
-}
 }
 
 /* This is called on an interupt so use locking.. Note Qisr2app_
@@ -951,14 +960,23 @@ fhandler_dev_dsp::Audio_in::waitfordata ()
   return true;
 }
 
+void fhandler_dev_dsp::Audio_in::default_buf_info (audio_buf_info *p,
+int rate, int bits, int 
channels)
+{
+  p->fragstotal = MAX_BLOCKS;
+  p->fragsize = blockSize (rate, bits, channels);
+  p->fragments = 0;
+  p->bytes = 0;
+}
+
 void
 fhandler_dev_dsp::Audio_in::buf_info (audio_buf_info *p,
  int rate, int bits, int channels)
 {
-  p->fragstotal = MAX_BLOCKS;
-  p->fragsize = blockSize (rate, bits, channels);
-  if (this && dev_)
+  if (dev_)
 {
+  p->fragstotal = MAX_BLOCKS;
+  p->fragsize = blockSize (rate, bits, channels);
   p->fragments = Qisr2app_->query ();
   if (pHdr_ != NULL)
p->bytes = pHdr_->dwBytesRecorded - bufferIndex_
@@ -968,8 +986,7 @@ fhandler_dev_dsp::Audio_in::buf_info (audio_buf_info *p,
 }
   else
 {
-  p->fragments = 0;
-  p->bytes = 0;
+  default_buf_info(p, rate, bits, channels);
 }
 }
 
@@ -1343,9 +1360,13 @@ fhandler_dev_dsp::_ioctl (unsigned int cmd, void *buf)
return -1;
  }
audio_buf_info *p = (audio_buf_info *) buf;
-   audio_out_->buf_info (p, audiofreq_, audiobits_, audiochannels_);
-   debug_printf ("buf=%p frags=%d fragsize=%d bytes=%d",
- buf, p->fragments, p->fragsize, p->bytes);
+if (audio_out_) {
+audio_out_->buf_info (p, audiofreq_, audiobits_, audiochannels_);
+} else {
+Audio_out::default_buf_info(p, audiofreq_, audiobits_, 
audiochannels_);
+}
+debug_printf ("buf=%p frags=%d fragsize=%d bytes=%d",
+  buf, p->fragments, p->fragsize, p->bytes);
return 0;
   }
 
@@ -1357,9 +1378,13 @@ fhandler_dev_dsp::_ioctl (unsigned int cmd, void *buf)
return -1;
  }
audio_buf_info *p = (audio_buf_info *) buf;
-   audio_in_->buf_info (p, audiofreq_, audiobits_, audiochannels_);
-   debug_printf ("buf=%p frags=%d fragsize=%d bytes=%d",
- buf, p->fragments, p->fragsize, p->bytes);
+if (audio_in_) {
+audio_in_->buf_info (p, audiofreq_, audiobits_, audiochannels_);
+} else {
+Audio_in::default_buf_info(p, audiofreq_, audiobits_, 
audiochannels_);
+}
+

[PATCH 12/12] cygwin: Remove workaround for GCC 6 null pointer check warnings

2017-09-16 Thread Ken Brown
---
 winsup/cygwin/Makefile.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 98727c019..add1de0e9 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -73,7 +73,7 @@ CRT0:=$(cygwin_build)/crt0.o
 #
 MT_SAFE:=@MT_SAFE@
 CCEXTRA=
-COMMON_CFLAGS=-MMD ${$(*F)_CFLAGS} -Werror -fno-delete-null-pointer-checks 
-fmerge-constants -ftracer $(CCEXTRA)
+COMMON_CFLAGS=-MMD ${$(*F)_CFLAGS} -Werror -fmerge-constants -ftracer 
$(CCEXTRA)
 ifeq ($(target_cpu),x86_64)
 COMMON_CFLAGS+=-mcmodel=small
 endif
-- 
2.14.1



[PATCH 06/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::commune_request

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/pinfo.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index e792a0a1c..a068bcc42 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -720,7 +720,7 @@ _pinfo::commune_request (__uint32_t code, ...)
   res.s = NULL;
   res.n = 0;
 
-  if (!this || !pid)
+  if (!pid)
 {
   set_errno (ESRCH);
   goto err;
-- 
2.14.1



[PATCH 07/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::pipe_fhandler

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/pinfo.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index a068bcc42..72aa658eb 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -819,7 +819,7 @@ out:
 fhandler_pipe *
 _pinfo::pipe_fhandler (int64_t unique_id, size_t &n)
 {
-  if (!this || !pid)
+  if (!pid)
 return NULL;
   if (pid == myself->pid)
 return NULL;
-- 
2.14.1



[PATCH 08/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::fd

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/fhandler_process.cc | 2 +-
 winsup/cygwin/pinfo.cc| 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/fhandler_process.cc 
b/winsup/cygwin/fhandler_process.cc
index 7f122fbe4..360d8ea81 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -391,7 +391,7 @@ format_process_fd (void *data, char *&destbuf)
  set_errno (ENOENT);
  return 0;
}
-  destbuf = p->fd (fd, fs);
+  destbuf = p ? p->fd (fd, fs) : NULL;
   if (!destbuf || !*destbuf)
{
  set_errno (ENOENT);
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 72aa658eb..044c4fc3c 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -832,7 +832,7 @@ char *
 _pinfo::fd (int fd, size_t &n)
 {
   char *s;
-  if (!this || !pid)
+  if (!pid)
 return NULL;
   if (pid != myself->pid)
 {
-- 
2.14.1



[PATCH 10/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::kill

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/signal.cc | 15 ---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
index fbd2b241e..016fce1de 100644
--- a/winsup/cygwin/signal.cc
+++ b/winsup/cygwin/signal.cc
@@ -260,7 +260,7 @@ _pinfo::kill (siginfo_t& si)
}
   this_pid = pid;
 }
-  else if (this && process_state == PID_EXITED)
+  else if (process_state == PID_EXITED)
 {
   this_process_state = process_state;
   this_pid = pid;
@@ -296,8 +296,17 @@ kill0 (pid_t pid, siginfo_t& si)
   syscall_printf ("signal %d out of range", si.si_signo);
   return -1;
 }
-
-  return (pid > 0) ? pinfo (pid)->kill (si) : kill_pgrp (-pid, si);
+  if (pid > 0)
+{
+  pinfo p (pid);
+  if (!p)
+   {
+ set_errno (ESRCH);
+ return -1;
+   }
+  return p->kill (si);
+}
+  return kill_pgrp (-pid, si);
 }
 
 int
-- 
2.14.1



[PATCH 04/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::cwd

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/fhandler_process.cc | 2 +-
 winsup/cygwin/pinfo.cc| 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/fhandler_process.cc 
b/winsup/cygwin/fhandler_process.cc
index 08cc7ea92..453e79b16 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -498,7 +498,7 @@ format_process_cwd (void *data, char *&destbuf)
   cfree (destbuf);
   destbuf = NULL;
 }
-  destbuf = p->cwd (fs);
+  destbuf = p ? p->cwd (fs) : NULL;
   if (!destbuf || !*destbuf)
 {
   destbuf = cstrdup ("");
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 9fe1b3a88..c28158168 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -930,7 +930,7 @@ char *
 _pinfo::cwd (size_t& n)
 {
   char *s = NULL;
-  if (!this || !pid)
+  if (!pid)
 return NULL;
   if (ISSTATE (this, PID_NOTCYGWIN))
 {
-- 
2.14.1



[PATCH 09/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::environ

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/fhandler_process.cc | 2 +-
 winsup/cygwin/pinfo.cc| 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/fhandler_process.cc 
b/winsup/cygwin/fhandler_process.cc
index 360d8ea81..eb5a523ff 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -583,7 +583,7 @@ format_process_environ (void *data, char *&destbuf)
   cfree (destbuf);
   destbuf = NULL;
 }
-  destbuf = p->environ (fs);
+  destbuf = p ? p->environ (fs) : NULL;
   if (!destbuf || !*destbuf)
 {
   destbuf = cstrdup ("");
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 044c4fc3c..7193f6884 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -1036,7 +1036,7 @@ char *
 _pinfo::environ (size_t& n)
 {
   char **env = NULL;
-  if (!this || !pid)
+  if (!pid)
 return NULL;
   if (ISSTATE (this, PID_NOTCYGWIN))
 {
-- 
2.14.1



[PATCH 05/12] cygwin: Remove comparison of 'this' to 'NULL' in _pinfo::cmdline

2017-09-16 Thread Ken Brown
Fix all callers.
---
 winsup/cygwin/external.cc | 2 +-
 winsup/cygwin/fhandler_process.cc | 2 +-
 winsup/cygwin/pinfo.cc| 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc
index c81bdc0fa..6aae32aea 100644
--- a/winsup/cygwin/external.cc
+++ b/winsup/cygwin/external.cc
@@ -339,7 +339,7 @@ cygwin_internal (cygwin_getinfo_types t, ...)
  size_t n;
  pid_t pid = va_arg (arg, pid_t);
  pinfo p (pid);
- res = (uintptr_t) p->cmdline (n);
+ res = (uintptr_t) (p ? p->cmdline (n) : NULL);
}
break;
   case CW_CHECK_NTSEC:
diff --git a/winsup/cygwin/fhandler_process.cc 
b/winsup/cygwin/fhandler_process.cc
index 453e79b16..7f122fbe4 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -518,7 +518,7 @@ format_process_cmdline (void *data, char *&destbuf)
   cfree (destbuf);
   destbuf = NULL;
 }
-  destbuf = p->cmdline (fs);
+  destbuf = p ? p->cmdline (fs) : NULL;
   if (!destbuf || !*destbuf)
 {
   destbuf = cstrdup ("");
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index c28158168..e792a0a1c 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -976,7 +976,7 @@ char *
 _pinfo::cmdline (size_t& n)
 {
   char *s = NULL;
-  if (!this || !pid)
+  if (!pid)
 return NULL;
   if (ISSTATE (this, PID_NOTCYGWIN))
 {
-- 
2.14.1



[PATCH] cygcheck: Fix parsing of file names containing colons

2017-10-25 Thread Ken Brown
Up to now the function winsup/utils/dump_setup.cc:base skips past
colons when parsing file names.  As a result, a line like

  foo foo-1:2.3-4.tar.bz2 1

in /etc/setup/installed.db would cause 'cygcheck -cd foo' to report 4
as the installed version of foo insted of 1:2.3-4.  This is not an
issue now, but it will become an issue when version numbers are
allowed to contain epochs.
---
 winsup/utils/dump_setup.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/utils/dump_setup.cc b/winsup/utils/dump_setup.cc
index 320d69fab..3922b18f8 100644
--- a/winsup/utils/dump_setup.cc
+++ b/winsup/utils/dump_setup.cc
@@ -56,7 +56,7 @@ base (const char *s)
   const char *rv = s;
   while (*s)
 {
-  if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
+  if ((*s == '/' || *s == '\\') && s[1])
rv = s + 1;
   s++;
 }
-- 
2.14.2



Re: [PATCH] cygcheck: Fix parsing of file names containing colons

2017-10-25 Thread Ken Brown

On 10/25/2017 8:19 AM, Corinna Vinschen wrote:

On Oct 25 14:11, Corinna Vinschen wrote:

Hi Ken,

On Oct 25 07:23, Ken Brown wrote:

Up to now the function winsup/utils/dump_setup.cc:base skips past
colons when parsing file names.  As a result, a line like

   foo foo-1:2.3-4.tar.bz2 1

in /etc/setup/installed.db would cause 'cygcheck -cd foo' to report 4
as the installed version of foo insted of 1:2.3-4.  This is not an
issue now, but it will become an issue when version numbers are
allowed to contain epochs.
---
  winsup/utils/dump_setup.cc | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/utils/dump_setup.cc b/winsup/utils/dump_setup.cc
index 320d69fab..3922b18f8 100644
--- a/winsup/utils/dump_setup.cc
+++ b/winsup/utils/dump_setup.cc
@@ -56,7 +56,7 @@ base (const char *s)
const char *rv = s;
while (*s)
  {
-  if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
+  if ((*s == '/' || *s == '\\') && s[1])


I think this is a simplified way to test for the colon in paths like
C:/foo/bar.  Nothing else makes sense in this context.

I'm not sure how much we care, but maybe we shoulkd fix the test to
ignore the colon only if it's the second character in the incoming
string?


Not "ignore", but "use as a delimiter" only as 2nd char in the input.


I'm not sure the distinction matters in this case, since the function is 
just trying to get the base name.  Anyway, how's the attached?


Ken
From 1354e67e12819519f9a5440f12ef893e4e0bf7a5 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Tue, 24 Oct 2017 18:21:53 -0400
Subject: [PATCH] cygcheck: Fix parsing of file names containing colons

Up to now the function winsup/utils/dump_setup.cc:base skips past
colons when parsing file names.  As a result, a line like

  foo foo-1:2.3-4.tar.bz2 1

in /etc/setup/installed.db would cause 'cygcheck -cd foo' to report 4
as the installed version of foo insted of 1:2.3-4.  This is not an
issue now, but it will become an issue when version numbers are
allowed to contain epochs.
---
 winsup/utils/dump_setup.cc | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/winsup/utils/dump_setup.cc b/winsup/utils/dump_setup.cc
index 320d69fab..d05817239 100644
--- a/winsup/utils/dump_setup.cc
+++ b/winsup/utils/dump_setup.cc
@@ -53,10 +53,12 @@ base (const char *s)
 {
   if (!s)
 return 0;
+  if (isalpha (*s) && s[1] == ':')
+s += 2;
   const char *rv = s;
   while (*s)
 {
-  if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
+  if ((*s == '/' || *s == '\\') && s[1])
rv = s + 1;
   s++;
 }
-- 
2.14.2



Re: [PATCH] cygcheck: Fix parsing of file names containing colons

2017-10-25 Thread Ken Brown

On 10/25/2017 10:19 AM, Corinna Vinschen wrote:

On Oct 25 09:38, Ken Brown wrote:

On 10/25/2017 8:19 AM, Corinna Vinschen wrote:

On Oct 25 14:11, Corinna Vinschen wrote:

Hi Ken,

On Oct 25 07:23, Ken Brown wrote:

Up to now the function winsup/utils/dump_setup.cc:base skips past
colons when parsing file names.  As a result, a line like

foo foo-1:2.3-4.tar.bz2 1

in /etc/setup/installed.db would cause 'cygcheck -cd foo' to report 4
as the installed version of foo insted of 1:2.3-4.  This is not an
issue now, but it will become an issue when version numbers are
allowed to contain epochs.
---
   winsup/utils/dump_setup.cc | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/utils/dump_setup.cc b/winsup/utils/dump_setup.cc
index 320d69fab..3922b18f8 100644
--- a/winsup/utils/dump_setup.cc
+++ b/winsup/utils/dump_setup.cc
@@ -56,7 +56,7 @@ base (const char *s)
 const char *rv = s;
 while (*s)
   {
-  if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
+  if ((*s == '/' || *s == '\\') && s[1])


I think this is a simplified way to test for the colon in paths like
C:/foo/bar.  Nothing else makes sense in this context.

I'm not sure how much we care, but maybe we shoulkd fix the test to
ignore the colon only if it's the second character in the incoming
string?


Not "ignore", but "use as a delimiter" only as 2nd char in the input.


I'm not sure the distinction matters in this case, since the function is
just trying to get the base name.  Anyway, how's the attached?


Fine, thanks.

But now that you mention it... why does parse_filename() call base() at
all?  The filenames in installed.db are just basenames anyway.  Does
that cover an older DB format we don't support anymore, perhaps?


It looks like parse_filename is more-or-less copied from the function 
with the same name in the setup sources (in filemanip.cc).  In that case 
there might be a good reason to call base; I'll have to look more closely.



I just wonder now if we should simply remove base() and the call to it.

Either way, you're right, the colon check is just useless, so your first
patch was entirely sufficient.

What do you think?  Stick to your patch or remove base()?


I vote for removing base.  The attached patch does this.

Ken
From f679462937faf263de682c47f8d8e73b0c7e4136 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Tue, 24 Oct 2017 18:21:53 -0400
Subject: [PATCH] winsup/utils/dump_setup.cc: Remove the function 'base'

This was called only on filenames in /etc/setup/installed.db, which
are all basenames anyway.  Moreover, base wasn't correctly handling
filenames containing colons.
---
 winsup/utils/dump_setup.cc | 17 +
 1 file changed, 1 insertion(+), 16 deletions(-)

diff --git a/winsup/utils/dump_setup.cc b/winsup/utils/dump_setup.cc
index 320d69fab..4415954f9 100644
--- a/winsup/utils/dump_setup.cc
+++ b/winsup/utils/dump_setup.cc
@@ -48,21 +48,6 @@ find_tar_ext (const char *path)
 return 0;
 }
 
-static char *
-base (const char *s)
-{
-  if (!s)
-return 0;
-  const char *rv = s;
-  while (*s)
-{
-  if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
-   rv = s + 1;
-  s++;
-}
-  return (char *) rv;
-}
-
 /* Parse a filename into package, version, and extension components. */
 int
 parse_filename (const char *in_fn, fileparse& f)
@@ -79,7 +64,7 @@ parse_filename (const char *in_fn, fileparse& f)
   strcpy (f.tail, fn + n);
   fn[n] = '\0';
   f.pkg[0] = f.what[0] = '\0';
-  p = base (fn);
+  p = fn;
   for (ver = p; *ver; ver++)
 if (*ver != '-')
   continue;
-- 
2.14.2



Re: [PATCH] Add FAQ 4.46 How do I fix find_fast_cwd warnings?

2017-11-12 Thread Ken Brown

On 11/12/2017 1:39 PM, Brian Inglis wrote:

Having responded to some of these posts and being prompted by the suggestion in
a reply to one by "Cyg simple", I attach an offering, in the off chance that
anyone affected might actually check the FAQ or find it in a search. ;^>


Even if they don't find it, we can refer them to the FAQ rather than 
re-writing variations on the same answer each time.  But your patch 
should be to winsup/doc/faq-using.xml.


Ken


Re: [PATCH] Add FAQ 4.46. How do I fix find_fast_cwd warnings?

2017-11-12 Thread Ken Brown

On 11/12/2017 4:27 PM, Brian Inglis wrote:

+Some ancient Cygwin releases asked users to report problems that were
+  difficult to diagnose to the mailing list with the message:
+
+find_fast_cwd: WARNING: Couldn't compute FAST_CWD pointer. Please 
report
+this problem to the public mailing listcyg...@cygwin.com
+
+These problems were fixed long ago in updated Cygwin releases.


The wording of the warning message was changed 3 years ago, in commit 
0793492.  I'm not sure that qualifies as ancient.  I also don't think 
it's accurate to refer to the problem as "difficult to diagnose" or to 
say that the problems "were fixed long ago".


The issue (Corinna will correct me if I'm wrong) is simply that new 
releases of Windows sometimes require changes in how Cygwin finds the 
fast_cwd pointer.  So users of old versions of Cygwin on new versions of 
Windows might have problems, and this can certainly happen again in the 
future.  But the FAQ doesn't need to go into that.  Why not just say 
what the warning currently says (see path.cc:find_fast_cwd()):


"This typically occurs if you're using an older Cygwin version on a 
newer Windows.  Please update to the latest available Cygwin version 
from https://cygwin.com/.  If the problem persists, please see 
https://cygwin.com/problems.html.";


You can also add your sentence about contacting the vendor who provided 
the old Cygwin release.


Ken


Re: [PATCH setup v4 6/6] Display area and location of official mirrors

2017-12-10 Thread Ken Brown

On 12/10/2017 1:40 PM, Brian Inglis wrote:

On 2017-12-10 10:49, Ken Brown wrote:

Mirrors from mirrors.lst have area and location info, which we now
display and add to the sort key.

You didn't increase the list box width - are the hosts visible without 
scrolling?


No, that was an oversight.  I'll fix that locally and use it in future 
versions (or in the commit, if this version is accepted).


Ken



Fix declaration of pthread_rwlock_* functions

2018-05-30 Thread Ken Brown
The attached patch fixes the second problem reported in 
https://cygwin.com/ml/cygwin/2018-05/msg00316.html, though I'm not sure 
it's the right fix.


Ken
From 4940baac08cd9339d771d9db90a880c61610ae4c Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Wed, 30 May 2018 16:19:01 -0400
Subject: [PATCH] Declare the pthread_rwlock_* functions if __cplusplus >=
 201402L

Some of these functions are used in the  C++ header.
---
 winsup/cygwin/include/pthread.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h
index 3dfc2bc80..fed616532 100644
--- a/winsup/cygwin/include/pthread.h
+++ b/winsup/cygwin/include/pthread.h
@@ -187,7 +187,7 @@ int pthread_spin_unlock (pthread_spinlock_t *);
 #endif
 
 /* RW Locks */
-#if __XSI_VISIBLE >= 500 || __POSIX_VISIBLE >= 200112
+#if __XSI_VISIBLE >= 500 || __POSIX_VISIBLE >= 200112 || __cplusplus >= 201402L
 int pthread_rwlock_destroy (pthread_rwlock_t *rwlock);
 int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t 
*attr);
 int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
-- 
2.17.0



Re: Fix declaration of pthread_rwlock_* functions

2018-06-01 Thread Ken Brown

On 6/1/2018 6:10 AM, Corinna Vinschen wrote:

On May 30 16:28, Ken Brown wrote:

The attached patch fixes the second problem reported in
https://cygwin.com/ml/cygwin/2018-05/msg00316.html, though I'm not sure it's
the right fix.

Ken



 From 4940baac08cd9339d771d9db90a880c61610ae4c Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Wed, 30 May 2018 16:19:01 -0400
Subject: [PATCH] Declare the pthread_rwlock_* functions if __cplusplus >=
  201402L

Some of these functions are used in the  C++ header.
---
  winsup/cygwin/include/pthread.h | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h
index 3dfc2bc80..fed616532 100644
--- a/winsup/cygwin/include/pthread.h
+++ b/winsup/cygwin/include/pthread.h
@@ -187,7 +187,7 @@ int pthread_spin_unlock (pthread_spinlock_t *);
  #endif
  
  /* RW Locks */

-#if __XSI_VISIBLE >= 500 || __POSIX_VISIBLE >= 200112
+#if __XSI_VISIBLE >= 500 || __POSIX_VISIBLE >= 200112 || __cplusplus >= 201402L
  int pthread_rwlock_destroy (pthread_rwlock_t *rwlock);
  int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t 
*attr);
  int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
--
2.17.0



Pushed.  Any text for winsup/cygwin/release/2.10.1, perhaps?


Attached.

Ken

From 661edafedeb09d6ead1d3249763dc3fc6d3de40f Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Fri, 1 Jun 2018 08:31:43 -0400
Subject: [PATCH] Cygwin: Add pthread_rwlock_* fix to release notes

---
 winsup/cygwin/release/2.10.1 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/winsup/cygwin/release/2.10.1 b/winsup/cygwin/release/2.10.1
index c133124ae..42d9d1110 100644
--- a/winsup/cygwin/release/2.10.1
+++ b/winsup/cygwin/release/2.10.1
@@ -29,3 +29,6 @@ Bug Fixes
 - Fix a stack alignment problem which may lead to spurious crashes after
   fork.
   Addresses: https://cygwin.com/ml/cygwin-patches/2018-q2/msg00016.html
+
+- Fix a g++ compilation problem with -std=c++14 or -std=c++17.
+  Addresses: https://cygwin.com/ml/cygwin/2018-05/msg00316.html
-- 
2.17.0



[PATCH 0/5] Implement clearenv

2018-06-04 Thread Ken Brown
This is a followup to https://cygwin.com/ml/cygwin/2018-05/msg00334.html.

In this patch series I attempt to implement the glibc extension
clearenv().  I also implement glibc's notion of environ==NULL being
shorthand for an empty environment.

Two questions:

1. I haven't yet absorbed what SIGFE means.  I arbitrarily decorated
   clearenv with SIGFE rather than NOSIGFE in common.din, but I don't
   know if that's right.

2. I guarded the declaration of clearenv() with __GNU_VISIBLE, but
   again I'm not sure about this.  On the one hand, clearenv() is a
   GNU extension, so __GNU_VISIBLE would seem to be the right guard.
   On the other hand, glibc declares clearenv() if _DEFAULT_SOURCE is
   defined, so maybe the guard should be relaxed if our goal is to
   emulate Linux.

Yaakov?

Ken Brown (5):
  Cygwin: Clarify some code in environ.cc
  Cygwin: Allow the environment pointer to be NULL
  Cygwin: Implement the GNU extension clearenv
  Cygwin: Remove workaround in environ.cc
  Cygwin: Document clearenv

 winsup/cygwin/common.din   |  1 +
 winsup/cygwin/environ.cc   | 45 ++
 winsup/cygwin/include/cygwin/stdlib.h  |  1 +
 winsup/cygwin/include/cygwin/version.h |  3 +-
 winsup/cygwin/release/2.10.1   |  1 +
 winsup/doc/posix.xml   |  1 +
 6 files changed, 44 insertions(+), 8 deletions(-)

-- 
2.17.0



[PATCH 5/5] Cygwin: Document clearenv

2018-06-04 Thread Ken Brown
---
 winsup/cygwin/include/cygwin/version.h | 3 ++-
 winsup/cygwin/release/2.10.1   | 1 +
 winsup/doc/posix.xml   | 1 +
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index f08707eea..2991ab858 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -494,12 +494,13 @@ details. */
   323: scanf %l[ conversion.
   324: Export sigtimedwait.
   325: Export catclose, catgets, catopen.
+  326: Export clearenv
 
   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 325
+#define CYGWIN_VERSION_API_MINOR 326
 
 /* 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/release/2.10.1 b/winsup/cygwin/release/2.10.1
index 42d9d1110..ef7d08256 100644
--- a/winsup/cygwin/release/2.10.1
+++ b/winsup/cygwin/release/2.10.1
@@ -1,6 +1,7 @@
 What's new:
 ---
 
+- New API: clearenv.
 
 What changed:
 -
diff --git a/winsup/doc/posix.xml b/winsup/doc/posix.xml
index 8b4bab1b0..0c95091ea 100644
--- a/winsup/doc/posix.xml
+++ b/winsup/doc/posix.xml
@@ -1284,6 +1284,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).
 asprintf_r
 basename   (see chapter "Implementation Notes")
 canonicalize_file_name
+clearenv
 clog10
 clog10f
 clog10l
-- 
2.17.0



[PATCH 3/5] Cygwin: Implement the GNU extension clearenv

2018-06-04 Thread Ken Brown
---
 winsup/cygwin/common.din  |  1 +
 winsup/cygwin/environ.cc  | 20 
 winsup/cygwin/include/cygwin/stdlib.h |  1 +
 3 files changed, 22 insertions(+)

diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index 6e8bf9185..426cf172c 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -306,6 +306,7 @@ cimag NOSIGFE
 cimagf NOSIGFE
 cimagl NOSIGFE
 cleanup_glue NOSIGFE
+clearenv SIGFE
 clearerr SIGFE
 clearerr_unlocked SIGFE
 clock SIGFE
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 8e6bbe561..3676bd9ea 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -720,6 +720,26 @@ unsetenv (const char *name)
   return -1;
 }
 
+/* Clear the environment.  */
+extern "C" int
+clearenv ()
+{
+  __try
+{
+  if (cur_environ () == lastenviron && lastenviron != NULL)
+   {
+ free (lastenviron);
+ lastenviron = NULL;
+   }
+  __cygwin_environ = NULL;
+  update_envptrs ();
+  return 0;
+}
+  __except (EFAULT) {}
+  __endtry
+  return -1;
+}
+
 /* Minimal list of Windows vars which must be converted to uppercase.
Either for POSIX compatibility of for backward compatibility with
existing applications. */
diff --git a/winsup/cygwin/include/cygwin/stdlib.h 
b/winsup/cygwin/include/cygwin/stdlib.h
index 845d2d81b..55d75e402 100644
--- a/winsup/cygwin/include/cygwin/stdlib.h
+++ b/winsup/cygwin/include/cygwin/stdlib.h
@@ -22,6 +22,7 @@ void  setprogname (const char *);
 
 #if __GNU_VISIBLE
 char *canonicalize_file_name (const char *);
+int clearenv ();
 #endif
 #if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112
 int unsetenv (const char *);
-- 
2.17.0



[PATCH 4/5] Cygwin: Remove workaround in environ.cc

2018-06-04 Thread Ken Brown
Commit ebd645e on 2001-10-03 made environ.cc:_addenv() add unneeded
space at the end of the environment block to "work around problems
with some buggy applications."  This clutters the code and is
presumably no longer needed.
---
 winsup/cygwin/environ.cc | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 3676bd9ea..7cdeded08 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -591,13 +591,11 @@ _addenv (const char *name, const char *value, int 
overwrite)
 {  /* Create new slot. */
   int sz = envsize (cur_environ ());
 
-  /* If sz == 0, we need two new slots, one for the terminating NULL.
-But we add two slots in all cases, as has been done since
-2001-10-03 (commit ebd645e) to "work around problems with
-some buggy applications." */
-  int allocsz = (sz + 2) * sizeof (char *);
+  /* If sz == 0, we need two slots, one for the terminating NULL. */
+  int newsz = sz == 0 ? 2 : sz + 1;
+  int allocsz = newsz * sizeof (char *);
 
-  offset = sz == 0 ? 0 : sz - 1;
+  offset = newsz - 2;
 
   /* Allocate space for additional element. */
   if (cur_environ () == lastenviron)
-- 
2.17.0



[PATCH 2/5] Cygwin: Allow the environment pointer to be NULL

2018-06-04 Thread Ken Brown
Following glibc, interpret this as meaning the environment is empty.
---
 winsup/cygwin/environ.cc | 29 ++---
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index b452d21a5..8e6bbe561 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -483,6 +483,9 @@ my_findenv (const char *name, int *offset)
   register char **p;
   const char *c;
 
+  if (cur_environ () == NULL)
+return NULL;
+
   c = name;
   len = 0;
   while (*c && *c != '=')
@@ -545,14 +548,18 @@ _getenv_r (struct _reent *, const char *name)
   return findenv_func (name, &offset);
 }
 
-/* Return size of environment block, including terminating NULL. */
+/* Return number of environment entries, including terminating NULL. */
 static int __stdcall
 envsize (const char * const *in_envp)
 {
   const char * const *envp;
+
+  if (in_envp == NULL)
+return 0;
+
   for (envp = in_envp; *envp; envp++)
 continue;
-  return (1 + envp - in_envp) * sizeof (const char *);
+  return 1 + envp - in_envp;
 }
 
 /* Takes similar arguments to setenv except that overwrite is
@@ -584,23 +591,23 @@ _addenv (const char *name, const char *value, int 
overwrite)
 {  /* Create new slot. */
   int sz = envsize (cur_environ ());
 
-  /* Allocate space for two new slots even though only one is needed.
-According to the commit message for commit ebd645e
-(2001-10-03), this is done to "work around problems with some
-buggy applications." */
-  int allocsz = sz + (2 * sizeof (char *));
+  /* If sz == 0, we need two new slots, one for the terminating NULL.
+But we add two slots in all cases, as has been done since
+2001-10-03 (commit ebd645e) to "work around problems with
+some buggy applications." */
+  int allocsz = (sz + 2) * sizeof (char *);
 
-  offset = (sz - 1) / sizeof (char *);
+  offset = sz == 0 ? 0 : sz - 1;
 
   /* Allocate space for additional element. */
   if (cur_environ () == lastenviron)
lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
allocsz);
   else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
-   __cygwin_environ = (char **) memcpy ((char **) lastenviron,
-__cygwin_environ, sz);
+   __cygwin_environ = (char **) memcpy (lastenviron, __cygwin_environ,
+sz * sizeof (char *));
 
-  if (!__cygwin_environ)
+  if (!lastenviron)
{
 #ifdef DEBUGGING
  try_to_debug ();
-- 
2.17.0



[PATCH 1/5] Cygwin: Clarify some code in environ.cc

2018-06-04 Thread Ken Brown
---
 winsup/cygwin/environ.cc | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 43225341c..b452d21a5 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -545,6 +545,7 @@ _getenv_r (struct _reent *, const char *name)
   return findenv_func (name, &offset);
 }
 
+/* Return size of environment block, including terminating NULL. */
 static int __stdcall
 envsize (const char * const *in_envp)
 {
@@ -582,11 +583,16 @@ _addenv (const char *name, const char *value, int 
overwrite)
   else
 {  /* Create new slot. */
   int sz = envsize (cur_environ ());
+
+  /* Allocate space for two new slots even though only one is needed.
+According to the commit message for commit ebd645e
+(2001-10-03), this is done to "work around problems with some
+buggy applications." */
   int allocsz = sz + (2 * sizeof (char *));
 
   offset = (sz - 1) / sizeof (char *);
 
-  /* Allocate space for additional element plus terminating NULL. */
+  /* Allocate space for additional element. */
   if (cur_environ () == lastenviron)
lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
allocsz);
-- 
2.17.0



Re: [PATCH 2/5] Cygwin: Allow the environment pointer to be NULL

2018-06-04 Thread Ken Brown

On 6/4/2018 3:36 PM, Ken Brown wrote:

Following glibc, interpret this as meaning the environment is empty.


Sorry, please hold off on reviewing this patch.  I just noticed that I 
missed at least one place (build_env()) where environ==NULL could cause 
a crash.  I need to fix this and try to make sure there are no others.


Ken


[PATCH v2 4/6] Cygwin: Remove workaround in environ.cc

2018-06-06 Thread Ken Brown
Commit ebd645e on 2001-10-03 made environ.cc:_addenv() add unneeded
space at the end of the environment block to "work around problems
with some buggy applications."  This clutters the code and is
presumably no longer needed.
---
 winsup/cygwin/environ.cc | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index bbe539816..67ead1dde 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -592,13 +592,11 @@ _addenv (const char *name, const char *value, int 
overwrite)
 {  /* Create new slot. */
   int sz = envsize (cur_environ ());
 
-  /* If sz == 0, we need two new slots, one for the terminating NULL.
-But we add two slots in all cases, as has been done since
-2001-10-03 (commit ebd645e) to "work around problems with
-some buggy applications." */
-  int allocsz = (sz + 2) * sizeof (char *);
+  /* If sz == 0, we need two new slots, one for the terminating NULL. */
+  int newsz = sz == 0 ? 2 : sz + 1;
+  int allocsz = newsz * sizeof (char *);
 
-  offset = sz == 0 ? 0 : sz - 1;
+  offset = newsz - 2;
 
   /* Allocate space for additional element. */
   if (cur_environ () == lastenviron)
-- 
2.17.0



[PATCH v2 6/6] Bump Cygwin DLL version to 2.11.0

2018-06-06 Thread Ken Brown
---
 winsup/cygwin/include/cygwin/version.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index 2991ab858..958acca3a 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -10,8 +10,8 @@ details. */
the Cygwin shared library".  This version is used to track important
changes to the DLL and is mainly informative in nature. */
 
-#define CYGWIN_VERSION_DLL_MAJOR 2010
-#define CYGWIN_VERSION_DLL_MINOR 1
+#define CYGWIN_VERSION_DLL_MAJOR 2011
+#define CYGWIN_VERSION_DLL_MINOR 0
 
 /* Major numbers before CYGWIN_VERSION_DLL_EPOCH are incompatible. */
 
-- 
2.17.0



[PATCH v2 2/6] Cygwin: Allow the environment pointer to be NULL

2018-06-06 Thread Ken Brown
Following glibc, interpret this as meaning the environment is empty.
---
 winsup/cygwin/environ.cc | 40 ++--
 winsup/cygwin/pinfo.cc   |  7 ---
 2 files changed, 30 insertions(+), 17 deletions(-)

diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index b452d21a5..06e1ced01 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -30,6 +30,7 @@ details. */
 #include "shared_info.h"
 #include "ntdll.h"
 
+/* If this is not NULL, it points to memory allocated by us. */
 static char **lastenviron;
 
 /* Parse CYGWIN options */
@@ -483,6 +484,9 @@ my_findenv (const char *name, int *offset)
   register char **p;
   const char *c;
 
+  if (cur_environ () == NULL)
+return NULL;
+
   c = name;
   len = 0;
   while (*c && *c != '=')
@@ -545,14 +549,18 @@ _getenv_r (struct _reent *, const char *name)
   return findenv_func (name, &offset);
 }
 
-/* Return size of environment block, including terminating NULL. */
+/* Return number of environment entries, including terminating NULL. */
 static int __stdcall
 envsize (const char * const *in_envp)
 {
   const char * const *envp;
+
+  if (in_envp == NULL)
+return 0;
+
   for (envp = in_envp; *envp; envp++)
 continue;
-  return (1 + envp - in_envp) * sizeof (const char *);
+  return 1 + envp - in_envp;
 }
 
 /* Takes similar arguments to setenv except that overwrite is
@@ -584,23 +592,22 @@ _addenv (const char *name, const char *value, int 
overwrite)
 {  /* Create new slot. */
   int sz = envsize (cur_environ ());
 
-  /* Allocate space for two new slots even though only one is needed.
-According to the commit message for commit ebd645e
-(2001-10-03), this is done to "work around problems with some
-buggy applications." */
-  int allocsz = sz + (2 * sizeof (char *));
+  /* If sz == 0, we need two new slots, one for the terminating NULL.
+But we add two slots in all cases, as has been done since
+2001-10-03 (commit ebd645e) to "work around problems with
+some buggy applications." */
+  int allocsz = (sz + 2) * sizeof (char *);
 
-  offset = (sz - 1) / sizeof (char *);
+  offset = sz == 0 ? 0 : sz - 1;
 
   /* Allocate space for additional element. */
   if (cur_environ () == lastenviron)
-   lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
+   lastenviron = __cygwin_environ = (char **) realloc (lastenviron,
allocsz);
-  else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
-   __cygwin_environ = (char **) memcpy ((char **) lastenviron,
-__cygwin_environ, sz);
-
-  if (!__cygwin_environ)
+  else if ((lastenviron = (char **) realloc (lastenviron, allocsz)) != 
NULL)
+   __cygwin_environ = (char **) memcpy (lastenviron, __cygwin_environ,
+sz * sizeof (char *));
+  if (!lastenviron)
{
 #ifdef DEBUGGING
  try_to_debug ();
@@ -1029,8 +1036,13 @@ build_env (const char * const *envp, PWCHAR &envblock, 
int &envc,
   char **dstp;
   bool saw_spenv[SPENVS_SIZE] = {0};
 
+  static char *const empty_env[] = { NULL };
+
   debug_printf ("envp %p", envp);
 
+  if (!envp)
+envp = empty_env;
+
   /* How many elements? */
   for (n = 0; envp[n]; n++)
 continue;
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index e4eef8b3c..6b6986c9e 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -677,11 +677,12 @@ commune_process (void *arg)
sigproc_printf ("processing PICOM_ENVIRON");
unsigned n = 0;
char **env = cur_environ ();
-   for (char **e = env; *e; e++)
- n += strlen (*e) + 1;
+   if (env)
+ for (char **e = env; *e; e++)
+   n += strlen (*e) + 1;
if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
  sigproc_printf ("WritePipeOverlapped sizeof argv failed, %E");
-   else
+   else if (env)
  for (char **e = env; *e; e++)
if (!WritePipeOverlapped (tothem, *e, strlen (*e) + 1, &nr, 1000L))
  {
-- 
2.17.0



[PATCH v2 3/6] Cygwin: Implement the GNU extension clearenv

2018-06-06 Thread Ken Brown
---
 winsup/cygwin/common.din  |  1 +
 winsup/cygwin/environ.cc  | 20 
 winsup/cygwin/include/cygwin/stdlib.h |  3 +++
 3 files changed, 24 insertions(+)

diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index 6e8bf9185..426cf172c 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -306,6 +306,7 @@ cimag NOSIGFE
 cimagf NOSIGFE
 cimagl NOSIGFE
 cleanup_glue NOSIGFE
+clearenv SIGFE
 clearerr SIGFE
 clearerr_unlocked SIGFE
 clock SIGFE
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 06e1ced01..bbe539816 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -720,6 +720,26 @@ unsetenv (const char *name)
   return -1;
 }
 
+/* Clear the environment.  */
+extern "C" int
+clearenv (void)
+{
+  __try
+{
+  if (cur_environ () == lastenviron)
+   {
+ free (lastenviron);
+ lastenviron = NULL;
+   }
+  __cygwin_environ = NULL;
+  update_envptrs ();
+  return 0;
+}
+  __except (EFAULT) {}
+  __endtry
+  return -1;
+}
+
 /* Minimal list of Windows vars which must be converted to uppercase.
Either for POSIX compatibility of for backward compatibility with
existing applications. */
diff --git a/winsup/cygwin/include/cygwin/stdlib.h 
b/winsup/cygwin/include/cygwin/stdlib.h
index 845d2d81b..e274b8b94 100644
--- a/winsup/cygwin/include/cygwin/stdlib.h
+++ b/winsup/cygwin/include/cygwin/stdlib.h
@@ -26,6 +26,9 @@ char *canonicalize_file_name (const char *);
 #if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112
 int unsetenv (const char *);
 #endif
+#if __MISC_VISIBLE
+int clearenv (void);
+#endif
 #if __XSI_VISIBLE
 char *ptsname (int);
 int grantpt (int);
-- 
2.17.0



[PATCH v2 0/6] Implement clearenv

2018-06-06 Thread Ken Brown
This is a followup to https://cygwin.com/ml/cygwin/2018-05/msg00334.html.

In this patch series I attempt to implement the glibc extension
clearenv(). I also implement glibc's notion of environ==NULL being
shorthand for an empty environment.

v2: In patch 2 I've tried harder to fix all the cases in which
environ==NULL could be a problem.  I did this by grepping the sources
for 'cur_environ' and '__cygwin_environ', but it's still possible that
I missed something.

I've also incorporated the changes suggested by Corinna and Yaakov.

Ken Brown (6):
  Cygwin: Clarify some code in environ.cc
  Cygwin: Allow the environment pointer to be NULL
  Cygwin: Implement the GNU extension clearenv
  Cygwin: Remove workaround in environ.cc
  Cygwin: Document clearenv and bump API minor
  Bump Cygwin DLL version to 2.11.0

 winsup/cygwin/common.din |  1 +
 winsup/cygwin/environ.cc | 56 +++-
 winsup/cygwin/include/cygwin/stdlib.h|  3 ++
 winsup/cygwin/include/cygwin/version.h   |  7 +--
 winsup/cygwin/pinfo.cc   |  7 +--
 winsup/cygwin/release/{2.10.1 => 2.11.0} |  1 +
 winsup/doc/new-features.xml  | 20 +
 winsup/doc/posix.xml |  1 +
 8 files changed, 80 insertions(+), 16 deletions(-)
 rename winsup/cygwin/release/{2.10.1 => 2.11.0} (97%)

-- 
2.17.0



[PATCH v2 1/6] Cygwin: Clarify some code in environ.cc

2018-06-06 Thread Ken Brown
---
 winsup/cygwin/environ.cc | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 43225341c..b452d21a5 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -545,6 +545,7 @@ _getenv_r (struct _reent *, const char *name)
   return findenv_func (name, &offset);
 }
 
+/* Return size of environment block, including terminating NULL. */
 static int __stdcall
 envsize (const char * const *in_envp)
 {
@@ -582,11 +583,16 @@ _addenv (const char *name, const char *value, int 
overwrite)
   else
 {  /* Create new slot. */
   int sz = envsize (cur_environ ());
+
+  /* Allocate space for two new slots even though only one is needed.
+According to the commit message for commit ebd645e
+(2001-10-03), this is done to "work around problems with some
+buggy applications." */
   int allocsz = sz + (2 * sizeof (char *));
 
   offset = (sz - 1) / sizeof (char *);
 
-  /* Allocate space for additional element plus terminating NULL. */
+  /* Allocate space for additional element. */
   if (cur_environ () == lastenviron)
lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
allocsz);
-- 
2.17.0



[PATCH v2 5/6] Cygwin: Document clearenv and bump API minor

2018-06-06 Thread Ken Brown
Also add earlier "What changed" items to new-features.xml.
---
 winsup/cygwin/include/cygwin/version.h   |  3 ++-
 winsup/cygwin/release/{2.10.1 => 2.11.0} |  1 +
 winsup/doc/new-features.xml  | 20 
 winsup/doc/posix.xml |  1 +
 4 files changed, 24 insertions(+), 1 deletion(-)
 rename winsup/cygwin/release/{2.10.1 => 2.11.0} (97%)

diff --git a/winsup/cygwin/include/cygwin/version.h 
b/winsup/cygwin/include/cygwin/version.h
index f08707eea..2991ab858 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -494,12 +494,13 @@ details. */
   323: scanf %l[ conversion.
   324: Export sigtimedwait.
   325: Export catclose, catgets, catopen.
+  326: Export clearenv
 
   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 325
+#define CYGWIN_VERSION_API_MINOR 326
 
 /* 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/release/2.10.1 b/winsup/cygwin/release/2.11.0
similarity index 97%
rename from winsup/cygwin/release/2.10.1
rename to winsup/cygwin/release/2.11.0
index 42d9d1110..ef7d08256 100644
--- a/winsup/cygwin/release/2.10.1
+++ b/winsup/cygwin/release/2.11.0
@@ -1,6 +1,7 @@
 What's new:
 ---
 
+- New API: clearenv.
 
 What changed:
 -
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index 59af6efc0..5029b7c08 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -4,6 +4,26 @@
 
 What's new and what changed in Cygwin
 
+What's new and what changed in 2.11
+
+
+
+
+SO_RCVTIMEO and SO_SNDTIMEO socket options are now honored.
+
+
+
+/proc/cpuinfo now reports L3 cache size on Intel CPUs.
+
+
+
+New API: clearenv.
+
+
+
+
+
+
 What's new and what changed in 2.10
 
 
diff --git a/winsup/doc/posix.xml b/winsup/doc/posix.xml
index 8b4bab1b0..0c95091ea 100644
--- a/winsup/doc/posix.xml
+++ b/winsup/doc/posix.xml
@@ -1284,6 +1284,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).
 asprintf_r
 basename   (see chapter "Implementation Notes")
 canonicalize_file_name
+clearenv
 clog10
 clog10f
 clog10l
-- 
2.17.0



Re: getfacl output

2018-07-23 Thread Ken Brown

[Redirecting to cygwin-patches.]

On 7/23/2018 11:06 AM, Corinna Vinschen wrote:

On Jul 23 10:43, Ken Brown wrote:

This is obviously very minor, but I bumped into it because of a failing
emacs test.

Cygwin's getfacl prints only one colon after "mask" and "other", but Linux's
prints two.  I'm sure this was done for a reason, but I'm wondering if it
would be better to follow Linux.


The original version was designed after Solaris documentation,
but the layout is supposed to look like Linux for a while, so
ther missing colon is a bug.


   I'll be glad to submit a patch.


Glad to review it :)


Attached.

Ken
From de841bf40ecdbf93e87d0900d4dd567af32b072f Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Mon, 23 Jul 2018 10:10:03 -0400
Subject: [PATCH] getfacl and setfacl: Align with Linux

Make getfacl print two colons instead of one after "other" and "mask".
Change the help text for setfacl to indicate that there can be either
one colon or two.
---
 winsup/utils/getfacl.c | 12 ++--
 winsup/utils/setfacl.c |  6 +++---
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/winsup/utils/getfacl.c b/winsup/utils/getfacl.c
index 57c58fb6a..363226d6e 100644
--- a/winsup/utils/getfacl.c
+++ b/winsup/utils/getfacl.c
@@ -98,14 +98,14 @@ usage (FILE * stream)
" user:name or uid:perm\n"
" group::perm\n"
" group:name or gid:perm\n"
-   " mask:perm\n"
-   " other:perm\n"
+   " mask::perm\n"
+   " other::perm\n"
" default:user::perm\n"
" default:user:name or uid:perm\n"
" default:group::perm\n"
" default:group:name or gid:perm\n"
-   " default:mask:perm\n"
-   " default:other:perm\n"
+   " default:mask::perm\n"
+   " default:other::perm\n"
"\n");
 }
 }
@@ -265,10 +265,10 @@ main (int argc, char **argv)
n += printf ("group:%s:", groupname (acls[i].a_id));
  break;
case CLASS_OBJ:
- printf ("mask:");
+ printf ("mask::");
  break;
case OTHER_OBJ:
- printf ("other:");
+ printf ("other::");
  break;
}
  n += printf ("%s", permstr (acls[i].a_perm));
diff --git a/winsup/utils/setfacl.c b/winsup/utils/setfacl.c
index 373265bf0..2577ab776 100644
--- a/winsup/utils/setfacl.c
+++ b/winsup/utils/setfacl.c
@@ -119,7 +119,7 @@ getaclentry (action_t action, char *c, aclent_t *ace)
 }
   else if (!(ace->a_type & (USER_OBJ | GROUP_OBJ)))
 {
-  /* Mask and other entries may contain an extra colon. */
+  /* Mask and other entries may contain one or two colons. */
   if (*c == ':')
++c;
 }
@@ -558,8 +558,8 @@ usage (FILE *stream)
 "u[ser]:uid:perm\n"
 "g[roup]::perm\n"
 "g[roup]:gid:perm\n"
-"m[ask]:perm\n"
-"o[ther]:perm\n"
+"m[ask]:[:]perm\n"
+"o[ther]:[:]perm\n"
 "\n"
 "  Default entries are like the above with the additional default 
identifier.\n"
 "  For example: \n"
-- 
2.17.0



Re: getfacl output

2018-07-23 Thread Ken Brown

On 7/23/2018 11:37 AM, Corinna Vinschen wrote:

On Jul 23 11:15, Ken Brown wrote:

[Redirecting to cygwin-patches.]

On 7/23/2018 11:06 AM, Corinna Vinschen wrote:

On Jul 23 10:43, Ken Brown wrote:

This is obviously very minor, but I bumped into it because of a failing
emacs test.

Cygwin's getfacl prints only one colon after "mask" and "other", but Linux's
prints two.  I'm sure this was done for a reason, but I'm wondering if it
would be better to follow Linux.


The original version was designed after Solaris documentation,
but the layout is supposed to look like Linux for a while, so
ther missing colon is a bug.


I'll be glad to submit a patch.


Glad to review it :)


Attached.



Pushed.  I just wonder if we shouldn't simplify getfacl to use
acl_to_text instead.


Yes, that makes sense.  I'll take a look.

Ken


Re: getfacl output

2018-07-24 Thread Ken Brown

On 7/23/2018 12:06 PM, Ken Brown wrote:

On 7/23/2018 11:37 AM, Corinna Vinschen wrote:

On Jul 23 11:15, Ken Brown wrote:

[Redirecting to cygwin-patches.]

On 7/23/2018 11:06 AM, Corinna Vinschen wrote:

On Jul 23 10:43, Ken Brown wrote:
This is obviously very minor, but I bumped into it because of a 
failing

emacs test.

Cygwin's getfacl prints only one colon after "mask" and "other", 
but Linux's
prints two.  I'm sure this was done for a reason, but I'm wondering 
if it

would be better to follow Linux.


The original version was designed after Solaris documentation,
but the layout is supposed to look like Linux for a while, so
ther missing colon is a bug.


    I'll be glad to submit a patch.


Glad to review it :)


Attached.



Pushed.  I just wonder if we shouldn't simplify getfacl to use
acl_to_text instead.


Yes, that makes sense.  I'll take a look.


Patch attached.

I thought it might be possible to simplify setfacl in a similar way, but 
I didn't see a way to do it.


Ken
From 89cc58e5c4787e4a01b6938256cc2fa0101d0313 Mon Sep 17 00:00:00 2001
From: Ken Brown 
Date: Mon, 23 Jul 2018 17:46:41 -0400
Subject: [PATCH] getfacl: Simplify by using acl_to_any_text

---
 winsup/utils/getfacl.c | 153 +++--
 1 file changed, 41 insertions(+), 112 deletions(-)

diff --git a/winsup/utils/getfacl.c b/winsup/utils/getfacl.c
index 363226d6e..08dfc0bf3 100644
--- a/winsup/utils/getfacl.c
+++ b/winsup/utils/getfacl.c
@@ -14,6 +14,8 @@ details. */
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -21,18 +23,6 @@ details. */
 
 static char *prog_name;
 
-char *
-permstr (mode_t perm)
-{
-  static char pbuf[4];
-
-  pbuf[0] = (perm & S_IROTH) ? 'r' : '-';
-  pbuf[1] = (perm & S_IWOTH) ? 'w' : '-';
-  pbuf[2] = (perm & S_IXOTH) ? 'x' : '-';
-  pbuf[3] = '\0';
-  return pbuf;
-}
-
 const char *
 username (uid_t uid)
 {
@@ -150,9 +140,9 @@ main (int argc, char **argv)
   int eopt = 0;
   int dopt = 0;
   int nopt = 0;
+  int options = 0;
   int istty = isatty (fileno (stdout));
   struct stat st;
-  aclent_t acls[MAX_ACL_ENTRIES];
 
   prog_name = program_invocation_short_name;
 
@@ -192,19 +182,26 @@ main (int argc, char **argv)
   usage (stderr);
   return 1;
 }
+  if (nopt)
+options |= TEXT_NUMERIC_IDS;
+  if (eopt > 0)
+options |= TEXT_ALL_EFFECTIVE;
+  else if (!eopt)
+options |= TEXT_SOME_EFFECTIVE;
+  if (istty)
+options |= TEXT_SMART_INDENT;
   for (; optind < argc; ++optind)
 {
-  int i, num_acls;
-  mode_t mask = S_IRWXO, def_mask = S_IRWXO;
+  acl_t access_acl = NULL, default_acl = NULL;
+  char *access_txt, *default_txt;
 
   if (stat (argv[optind], &st)
- || (num_acls = acl (argv[optind], GETACL, MAX_ACL_ENTRIES, acls)) < 0)
-   {
- fprintf (stderr, "%s: %s: %s\n",
-  prog_name, argv[optind], strerror (errno));
- ret = 2;
- continue;
-   }
+ || (!dopt
+ && !(access_acl = acl_get_file (argv[optind], ACL_TYPE_ACCESS)))
+ || (!aopt && S_ISDIR (st.st_mode)
+ && !(default_acl = acl_get_file (argv[optind],
+  ACL_TYPE_DEFAULT
+   goto err;
   if (!copt)
{
  printf ("# file: %s\n", argv[optind]);
@@ -223,103 +220,35 @@ main (int argc, char **argv)
 (st.st_mode & S_ISGID) ? 's' : '-',
 (st.st_mode & S_ISVTX) ? 't' : '-');
}
-  for (i = 0; i < num_acls; ++i)
-   {
- if (acls[i].a_type == CLASS_OBJ)
-   mask = acls[i].a_perm;
- else if (acls[i].a_type == DEF_CLASS_OBJ)
-   def_mask = acls[i].a_perm;
-   }
-  for (i = 0; i < num_acls; ++i)
+  if (access_acl)
{
- int n = 0;
- int print_effective = 0;
- mode_t effective = acls[i].a_perm;
-
- if (acls[i].a_type & ACL_DEFAULT)
-   {
- if (aopt)
-   continue;
- n += printf ("default:");
-   }
- else if (dopt)
-   continue;
- switch (acls[i].a_type & ~ACL_DEFAULT)
+ if (!(access_txt = acl_to_any_text (access_acl, NULL, '\n', options)))
{
-   case USER_OBJ:
- printf ("user::");
- break;
-   case USER:
- if (nopt)
-   n += printf ("user:%lu:", (unsigned long)acls[i].a_id);
- else
-   n += printf ("user:%s:", username (acls[i].a_id));
- break;
-   case GROUP_OBJ:
- n += printf ("g

[PATCH] setfacl: Rename the option --file to --set-file, as on Linux

2018-08-16 Thread Ken Brown
Retain --file as an undocumented option for backwards compatibility.
---
 winsup/cygwin/release/2.11.0 | 2 ++
 winsup/doc/new-features.xml  | 4 
 winsup/doc/utils.xml | 4 ++--
 winsup/utils/setfacl.c   | 5 +++--
 4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/winsup/cygwin/release/2.11.0 b/winsup/cygwin/release/2.11.0
index 2d86dea3f..171b5d4d0 100644
--- a/winsup/cygwin/release/2.11.0
+++ b/winsup/cygwin/release/2.11.0
@@ -18,6 +18,8 @@ What changed:
 
 - Drop denormal-operand exception from FE_ALL_EXCEPT, as on Linux.
 
+- Rename the --file option of setfacl(1) to --set-file, as on Linux.
+
 
 Bug Fixes
 -
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index ad45a56e0..0107f75e2 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -30,6 +30,10 @@ New Header: .
 Drop denormal-operand exception from FE_ALL_EXCEPT, as on Linux.
 
 
+
+Rename the --file option of setfacl(1) to --set-file, as on Linux.
+
+
 
 
 
diff --git a/winsup/doc/utils.xml b/winsup/doc/utils.xml
index 948db5832..182134379 100644
--- a/winsup/doc/utils.xml
+++ b/winsup/doc/utils.xml
@@ -1968,7 +1968,7 @@ setfacl [-n] {[-bk]|[-x acl_entries] [-m acl_entries]} 
FILE...
   
   -b, --remove-all   remove all extended ACL entries\n"
   -x, --delete   delete one or more specified ACL entries\n"
-  -f, --file set ACL entries for FILE to ACL entries read\n"
+  -f, --set-file set ACL entries for FILE to ACL entries read\n"
  from ACL_FILE\n"
   -k, --remove-default   remove all default ACL entries\n"
   -m, --modify   modify one or more specified ACL entries\n"
@@ -2035,7 +2035,7 @@ At least one of (-b, -x, -f, -k, -m, -s) must be 
specified\n"
  d[efault]:o[ther][:]
  
 
- -f,--file Take the Acl_entries
+ -f,--set-file Take the 
Acl_entries
   from ACL_FILE one per line. Whitespace characters are ignored, and the
   character "#" may be used to start a comment. The special filename "-"
   indicates reading from stdin. Note that you can use this with
diff --git a/winsup/utils/setfacl.c b/winsup/utils/setfacl.c
index 2577ab776..926581a39 100644
--- a/winsup/utils/setfacl.c
+++ b/winsup/utils/setfacl.c
@@ -536,7 +536,7 @@ usage (FILE *stream)
 "\n"
 "  -b, --remove-all   remove all extended ACL entries\n"
 "  -x, --delete   delete one or more specified ACL entries\n"
-"  -f, --file set ACL entries for FILE to ACL entries read\n"
+"  -f, --set-file set ACL entries for FILE to ACL entries read\n"
 " from ACL_FILE\n"
 "  -k, --remove-default   remove all default ACL entries\n"
 "  -m, --modify   modify one or more specified ACL entries\n"
@@ -595,7 +595,7 @@ usage (FILE *stream)
 "d[efault]:m[ask][:]\n"
 "d[efault]:o[ther][:]\n"
 "\n"
-"-f, --file\n"
+"-f, --set-file\n"
 "  Take the Acl_entries from ACL_FILE one per line.  Whitespace characters 
are\n"
 "  ignored, and the character \"#\" may be used to start a comment.  The 
special\n"
 "  filename \"-\" indicates reading from stdin.\n"
@@ -652,6 +652,7 @@ usage (FILE *stream)
 struct option longopts[] = {
   {"remove-all", no_argument, NULL, 'b'},
   {"delete", required_argument, NULL, 'x'},
+  {"set-file", required_argument, NULL, 'f'},
   {"file", required_argument, NULL, 'f'},
   {"remove-default", no_argument, NULL, 'k'},
   {"modify", required_argument, NULL, 'm'},
-- 
2.17.0



[PATCH] Cygwin: af_unix_spinlock_t: add initializer

2019-01-10 Thread Ken Brown
Also fix a typo.
---
 winsup/cygwin/fhandler.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index d02b9a913..7e460701c 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -832,9 +832,10 @@ class fhandler_socket_local: public fhandler_socket_wsock
 /* Sharable spinlock with low CPU profile.  These locks are NOT recursive! */
 class af_unix_spinlock_t
 {
-  LONG  locked;  /* 0 oder 1 */
+  LONG  locked;  /* 0 or 1 */
 
 public:
+  af_unix_spinlock_t () : locked (0) {}
   void lock ()
   {
 LONG ret = InterlockedExchange (&locked, 1);
-- 
2.17.0



Re: [PATCH] Cygwin: af_unix_spinlock_t: add initializer

2019-01-10 Thread Ken Brown
On 1/10/2019 1:02 PM, Corinna Vinschen wrote:
> On Jan 10 17:56, Ken Brown wrote:
>> Also fix a typo.
>> ---
>>   winsup/cygwin/fhandler.h | 3 ++-
>>   1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
>> index d02b9a913..7e460701c 100644
>> --- a/winsup/cygwin/fhandler.h
>> +++ b/winsup/cygwin/fhandler.h
>> @@ -832,9 +832,10 @@ class fhandler_socket_local: public 
>> fhandler_socket_wsock
>>   /* Sharable spinlock with low CPU profile.  These locks are NOT recursive! 
>> */
>>   class af_unix_spinlock_t
>>   {
>> -  LONG  locked;  /* 0 oder 1 */
>> +  LONG  locked;  /* 0 or 1 */
> 
> Huh.
> 
>>   public:
>> +  af_unix_spinlock_t () : locked (0) {}
> 
> Why do we need that?  The spinlock is created as part of a shared mem
> region which gets initialized to all zero, no?  Or do you plan to use it
> outside of this scenario?

At the moment I'm using it in the new FIFO code, and I'm not sure yet whether 
it 
will eventually be in shared memory.  (Until I get things working, I'm 
postponing thinking about whether I need shared memory.)

Would it be better to use some other kind of spinlock until I know for sure 
that 
I need shared memory?  My only reason for choosing af_unix_spinlock_t is that I 
was copying code from fhandler_socket_unix, and this saved me the trouble of 
learning about other kinds of spinlocks.

Ken


Re: [PATCH] Cygwin: af_unix_spinlock_t: add initializer

2019-01-10 Thread Ken Brown
On 1/10/2019 3:16 PM, Corinna Vinschen wrote:
> On Jan 10 18:36, Ken Brown wrote:
>> On 1/10/2019 1:02 PM, Corinna Vinschen wrote:
>>> On Jan 10 17:56, Ken Brown wrote:
>>>> Also fix a typo.
>>>> ---
>>>>winsup/cygwin/fhandler.h | 3 ++-
>>>>1 file changed, 2 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
>>>> index d02b9a913..7e460701c 100644
>>>> --- a/winsup/cygwin/fhandler.h
>>>> +++ b/winsup/cygwin/fhandler.h
>>>> @@ -832,9 +832,10 @@ class fhandler_socket_local: public 
>>>> fhandler_socket_wsock
>>>>/* Sharable spinlock with low CPU profile.  These locks are NOT 
>>>> recursive! */
>>>>class af_unix_spinlock_t
>>>>{
>>>> -  LONG  locked;  /* 0 oder 1 */
>>>> +  LONG  locked;  /* 0 or 1 */
>>>
>>> Huh.
>>>
>>>>public:
>>>> +  af_unix_spinlock_t () : locked (0) {}
>>>
>>> Why do we need that?  The spinlock is created as part of a shared mem
>>> region which gets initialized to all zero, no?  Or do you plan to use it
>>> outside of this scenario?
>>
>> At the moment I'm using it in the new FIFO code, and I'm not sure yet 
>> whether it
>> will eventually be in shared memory.  (Until I get things working, I'm
>> postponing thinking about whether I need shared memory.)
>>
>> Would it be better to use some other kind of spinlock until I know for sure 
>> that
>> I need shared memory?  My only reason for choosing af_unix_spinlock_t is 
>> that I
>> was copying code from fhandler_socket_unix, and this saved me the trouble of
>> learning about other kinds of spinlocks.
> 
> The above patch shouldn't hurt in the least since it's not used anyway
> when allocating the shared mem region used by the AF_UNIX socket code.
> If it helps you, I can push it, no problem.
> 
> Just make sure this spinlock is the right thing for you.  The idea here
> was to have a fast, sharable(*) lock without context switching, only
> guarding small code blocks which don't hang due to resource starving.
> 
> If you have to guard more complex code chunks, it might be better to
> use a kernel locking object like mutex or semaphore.
> 
> 
> So, push or no push?

Please push.  Thanks.

Ken


[PATCH fifo 0/8] Allow a FIFO to have multiple writers

2019-03-22 Thread Ken Brown
Currently a FIFO can have only one writer.  A second attempt to open
the FIFO for writing blocks while fhandler_fifo::open waits for the
read_ready event to be signalled.

This patch series tries to fix the problem by having the reader open
multiple instances of the Windows named pipe underlying the FIFO.
When the FIFO is opened for reading, a 'listen_client' thread is
created that listens for clients (writers) to connect to the pipe.  It
creates new pipe instances as needed.

fhandler_fifo::raw_read loops through the connected writers, checking
for input.

I've tested it by running the fifo client and server programs from
Chapter 44 of the book "The Linux Programming Interface: Linux and
UNIX System Programming Handbook" by Michael Kerrisk.  (See
https://cygwin.com/ml/cygwin/2015-03/msg00047.html for simplified
versions of these programs.)  These work as on Linux.

I've also tried the test given in
http://www.cygwin.org/ml/cygwin/2015-12/msg00311.html.  It works as on
Linux also.

TODO:

 - Try to get the code to work for duplexers (FIFOs opened for reading
   and writing).  I haven't thought about this at all yet.

 - Think about what it would take to allow multiple readers.  I'm not
   very optimistic about this, but my impression is that the
   multiple-writer case is more important in practice.

Ken

Ken Brown (8):
  Cygwin: FIFO: stop using overlapped I/O
  Cygwin: FIFO: allow multiple writers
  Cygwin: FIFO: add a spinlock
  Cygwin: FIFO: improve EOF detection
  Cygwin: FIFO: update clone and dup
  Cygwin: FIFO: update fixup_after_fork
  Cygwin: FIFO: update set_close_on_exec
  Cygwin: FIFO: update select

 winsup/cygwin/fhandler.h   |  58 ++-
 winsup/cygwin/fhandler_fifo.cc | 732 +++--
 winsup/cygwin/select.cc| 161 +++-
 winsup/cygwin/select.h |   7 +
 4 files changed, 819 insertions(+), 139 deletions(-)

-- 
2.17.0



[PATCH fifo 1/8] Cygwin: FIFO: stop using overlapped I/O

2019-03-22 Thread Ken Brown
Make fhandler_fifo a derived class of fhandler_base instead of
fhandler_base_overlapped.

Replace the create_pipe macro, which is based on
fhandler_pipe::create, by new create_pipe and open_pipe methods.
These use NT functions instead of Win32 functions.  Replace fifo_name
by get_pipe_name, which returns a pointer to a UNICODE_STRING.

Remove the fnevent macro, which would now be needed only once.

Add a raw_write method, adapted from fhandler_base::raw_write.

Adapt all functions to the changes above.
---
 winsup/cygwin/fhandler.h   |  13 +-
 winsup/cygwin/fhandler_fifo.cc | 337 ++---
 2 files changed, 236 insertions(+), 114 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 0da87e985..57e97c277 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1234,14 +1234,21 @@ public:
   }
 };
 
-class fhandler_fifo: public fhandler_base_overlapped
+#define CYGWIN_FIFO_PIPE_NAME_LEN 47
+
+class fhandler_fifo: public fhandler_base
 {
   HANDLE read_ready;
   HANDLE write_ready;
+  UNICODE_STRING pipe_name;
+  WCHAR pipe_name_buf[CYGWIN_FIFO_PIPE_NAME_LEN + 1];
   bool __reg2 wait (HANDLE);
-  char __reg2 *fifo_name (char *, const char *);
+  NTSTATUS npfs_handle (HANDLE &);
+  HANDLE create_pipe ();
+  NTSTATUS open_pipe ();
 public:
   fhandler_fifo ();
+  PUNICODE_STRING get_pipe_name ();
   int open (int, mode_t);
   off_t lseek (off_t offset, int whence);
   int close ();
@@ -1249,6 +1256,7 @@ public:
   bool isfifo () const { return true; }
   void set_close_on_exec (bool val);
   void __reg3 raw_read (void *ptr, size_t& ulen);
+  ssize_t __reg3 raw_write (const void *ptr, size_t ulen);
   bool arm (HANDLE h);
   void fixup_after_fork (HANDLE);
   int __reg2 fstatvfs (struct statvfs *buf);
@@ -1262,7 +1270,6 @@ public:
   {
 x->pc.free_strings ();
 *reinterpret_cast (x) = *this;
-reinterpret_cast (x)->atomic_write_buf = NULL;
 x->reset (this);
   }
 
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 5733ec778..cb269e344 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -7,6 +7,7 @@
details. */
 
 #include "winsup.h"
+#include 
 #include "miscfuncs.h"
 
 #include "cygerrno.h"
@@ -21,26 +22,32 @@
 #include "ntdll.h"
 #include "cygwait.h"
 
+/* This is only to be used for writers.  When reading,
+STATUS_PIPE_EMPTY simply means there's no data to be read. */
+#define STATUS_PIPE_IS_CLOSED(status)  \
+   ({ NTSTATUS _s = (status); \
+  _s == STATUS_PIPE_CLOSING \
+  || _s == STATUS_PIPE_BROKEN \
+  || _s == STATUS_PIPE_EMPTY; })
+
 fhandler_fifo::fhandler_fifo ():
-  fhandler_base_overlapped (),
+  fhandler_base (),
   read_ready (NULL), write_ready (NULL)
 {
-  max_atomic_write = DEFAULT_PIPEBUFSIZE;
+  pipe_name_buf[0] = L'\0';
   need_fork_fixup (true);
 }
 
-#define fnevent(w) fifo_name (npbuf, w "-event")
-#define fnpipe() fifo_name (npbuf, "fifo")
-#define create_pipe(r, w) \
-  fhandler_pipe::create (sa_buf, (r), (w), 0, fnpipe (), open_mode)
-
-char *
-fhandler_fifo::fifo_name (char *buf, const char *what)
+PUNICODE_STRING
+fhandler_fifo::get_pipe_name ()
 {
-  /* Generate a semi-unique name to associate with this fifo. */
-  __small_sprintf (buf, "%s.%08x.%016X", what, get_dev (),
-  get_ino ());
-  return buf;
+  if (!pipe_name_buf[0])
+{
+  __small_swprintf (pipe_name_buf, L"%S-fifo.%08x.%016X",
+   &cygheap->installation_key, get_dev (), get_ino ());
+  RtlInitUnicodeString (&pipe_name, pipe_name_buf);
+}
+  return &pipe_name;
 }
 
 inline PSECURITY_ATTRIBUTES
@@ -56,10 +63,8 @@ fhandler_fifo::arm (HANDLE h)
   const char *what;
   if (h == read_ready)
 what = "reader";
-  else if (h == write_ready)
-what = "writer";
   else
-what = "overlapped event";
+what = "writer";
   debug_only_printf ("arming %s", what);
 #endif
 
@@ -73,17 +78,113 @@ fhandler_fifo::arm (HANDLE h)
   return res;
 }
 
+NTSTATUS
+fhandler_fifo::npfs_handle (HANDLE &nph)
+{
+  static NO_COPY SRWLOCK npfs_lock;
+  static NO_COPY HANDLE npfs_dirh;
+
+  NTSTATUS status = STATUS_SUCCESS;
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
+
+  /* Lockless after first call. */
+  if (npfs_dirh)
+{
+  nph = npfs_dirh;
+  return STATUS_SUCCESS;
+}
+  AcquireSRWLockExclusive (&npfs_lock);
+  if (!npfs_dirh)
+{
+  InitializeObjectAttributes (&attr, &ro_u_npfs, 0, NULL, NULL);
+  status = NtOpenFile (&npfs_dirh, FILE_READ_ATTRIBUTES | SYNCHRONIZE,
+  &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
+  0);
+}
+  ReleaseSRWLockExclusive (&npfs_lock);
+  if (NT_SUCCESS (status))
+nph = npfs_dirh;
+  return status;
+}
+
+/* Called when pipe is opened for reading. */
+HANDLE
+fhandler_fifo::create_pipe ()
+{
+  NTSTATUS status;
+  HANDLE npfsh;
+  HANDLE ph = NULL;
+  A

[PATCH fifo 3/8] Cygwin: FIFO: add a spinlock

2019-03-22 Thread Ken Brown
Don't let listen_client_thread and raw_read access the client list
simultaneously.
---
 winsup/cygwin/fhandler.h   |  3 +++
 winsup/cygwin/fhandler_fifo.cc | 34 +-
 2 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index e7c4af6a1..997dc0b6d 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1267,6 +1267,7 @@ class fhandler_fifo: public fhandler_base
   WCHAR pipe_name_buf[CYGWIN_FIFO_PIPE_NAME_LEN + 1];
   fifo_client_handler client[MAX_CLIENTS];
   int nclients, nconnected;
+  af_unix_spinlock_t _fifo_client_lock;
   bool __reg2 wait (HANDLE);
   NTSTATUS npfs_handle (HANDLE &);
   HANDLE create_pipe_instance (bool);
@@ -1278,6 +1279,8 @@ public:
   fhandler_fifo ();
   PUNICODE_STRING get_pipe_name ();
   DWORD listen_client_thread ();
+  void fifo_client_lock () { _fifo_client_lock.lock (); }
+  void fifo_client_unlock () { _fifo_client_lock.unlock (); }
   int open (int, mode_t);
   off_t lseek (off_t offset, int whence);
   int close ();
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index e91e88050..b0016ee90 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -349,13 +349,17 @@ fhandler_fifo::listen_client_thread ()
   int i;
   DWORD wait_ret;
 
+  fifo_client_lock ();
   found = false;
   for (i = 0; i < nclients; i++)
switch (client[i].state)
  {
  case fc_invalid:
if (disconnect_and_reconnect (i) < 0)
- goto errout;
+ {
+   fifo_client_unlock ();
+   goto errout;
+ }
/* Fall through. */
  case fc_connected:
w[i] = client[i].dummy_evt;
@@ -369,13 +373,15 @@ fhandler_fifo::listen_client_thread ()
break;
  }
   w[nclients] = lct_termination_evt;
+  int res = 0;
   if (!found)
-   {
- if (add_client () < 0)
-   goto errout;
- else
-   continue;
-   }
+   res = add_client ();
+  fifo_client_unlock ();
+  if (res < 0)
+   goto errout;
+  else if (!found)
+   continue;
+
   if (!arm (read_ready))
{
  __seterrno ();
@@ -391,9 +397,11 @@ fhandler_fifo::listen_client_thread ()
return 0;
   else
{
+ fifo_client_lock ();
  client[i].state = fc_connected;
  nconnected++;
  set_pipe_non_blocking (client[i].fh->get_handle (), true);
+ fifo_client_unlock ();
  yield ();
}
 }
@@ -664,6 +672,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
}
 
   /* Poll the connected clients for input. */
+  fifo_client_lock ();
   for (int i = 0; i < nclients; i++)
if (client[i].state == fc_connected)
  {
@@ -671,15 +680,22 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
client[i].fh->fhandler_base::raw_read (in_ptr, len);
ssize_t nread = (ssize_t) len;
if (nread > 0)
- return;
+ {
+   fifo_client_unlock ();
+   return;
+ }
else if (nread < 0 && GetLastError () != ERROR_NO_DATA)
- goto errout;
+ {
+   fifo_client_unlock ();
+   goto errout;
+ }
else if (nread == 0) /* Client has disconnected. */
  {
client[i].state = fc_invalid;
nconnected--;
  }
  }
+  fifo_client_unlock ();
   if (is_nonblocking ())
{
  set_errno (EAGAIN);
-- 
2.17.0



[PATCH fifo 8/8] Cygwin: FIFO: update select

2019-03-22 Thread Ken Brown
Add static functions peek_fifo, thread_fifo, start_thread_fifo, and
fifo_cleanup to select.cc.  These are based on the corresponding pipe
functions, the main difference being that peek_fifo loops through the
connected clients to see if any of them have data available for
reading.

Add the fhandler_fifo methods select_read, select_write, and
select_except.

Add accessor methods get_nclients, get_handle, and is_connected that
are needed by peek_fifo.
---
 winsup/cygwin/fhandler.h |   4 +
 winsup/cygwin/select.cc  | 161 +++
 winsup/cygwin/select.h   |   7 ++
 3 files changed, 157 insertions(+), 15 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 0ebc44e0d..f6982f0ba 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1278,6 +1278,10 @@ class fhandler_fifo: public fhandler_base
 public:
   fhandler_fifo ();
   bool hit_eof ();
+  int get_nclients () const { return nclients; }
+  HANDLE& get_handle () { return fhandler_base::get_handle (); }
+  HANDLE get_handle (int i) const { return client[i].fh->get_handle (); }
+  bool is_connected (int i) const { return client[i].state == fc_connected; }
   PUNICODE_STRING get_pipe_name ();
   DWORD listen_client_thread ();
   void fifo_client_lock () { _fifo_client_lock.lock (); }
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 59325860d..991494aa8 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -822,17 +822,148 @@ fhandler_pipe::select_except (select_stuff *ss)
   return s;
 }
 
+static int
+peek_fifo (select_record *s, bool from_select)
+{
+  if (cygheap->fdtab.not_open (s->fd))
+{
+  s->thread_errno = EBADF;
+  return -1;
+}
+
+  int gotone = 0;
+  fhandler_fifo *fh = (fhandler_fifo *) s->fh;
+
+  if (s->read_selected)
+{
+  if (s->read_ready)
+   {
+ select_printf ("%s, already ready for read", fh->get_name ());
+ gotone = 1;
+ goto out;
+   }
+
+  if (fh->get_readahead_valid ())
+   {
+ select_printf ("readahead");
+ gotone = s->read_ready = true;
+ goto out;
+   }
+
+  if (fh->hit_eof ())
+   {
+ select_printf ("read: %s, saw EOF", fh->get_name ());
+ gotone = s->read_ready = true;
+ if (s->except_selected)
+   gotone += s->except_ready = true;
+ goto out;
+   }
+
+  fh->fifo_client_lock ();
+  for (int i = 0; i < fh->get_nclients (); i++)
+   if (fh->is_connected (i))
+ {
+   int n = pipe_data_available (s->fd, fh, fh->get_handle (i),
+false);
+   if (n > 0)
+ {
+   select_printf ("read: %s, ready for read: avail %d, client %d",
+  fh->get_name (), n, i);
+   fh->fifo_client_unlock ();
+   gotone += s->read_ready = true;
+   goto out;
+ }
+ }
+  fh->fifo_client_unlock ();
+}
+out:
+  if (s->write_selected)
+{
+  gotone += s->write_ready
+   = pipe_data_available (s->fd, fh, fh->get_handle (), true);
+  select_printf ("write: %s, gotone %d", fh->get_name (), gotone);
+}
+  return gotone;
+}
+
+static int start_thread_fifo (select_record *me, select_stuff *stuff);
+
+static DWORD WINAPI
+thread_fifo (void *arg)
+{
+  select_fifo_info *pi = (select_fifo_info *) arg;
+  DWORD sleep_time = 0;
+  bool looping = true;
+
+  while (looping)
+{
+  for (select_record *s = pi->start; (s = s->next); )
+   if (s->startup == start_thread_fifo)
+ {
+   if (peek_fifo (s, true))
+ looping = false;
+   if (pi->stop_thread)
+ {
+   select_printf ("stopping");
+   looping = false;
+   break;
+ }
+ }
+  if (!looping)
+   break;
+  Sleep (sleep_time >> 3);
+  if (sleep_time < 80)
+   ++sleep_time;
+  if (pi->stop_thread)
+   break;
+}
+  return 0;
+}
+
+static int
+start_thread_fifo (select_record *me, select_stuff *stuff)
+{
+  select_fifo_info *pi = stuff->device_specific_fifo;
+  if (pi->start)
+me->h = *((select_fifo_info *) stuff->device_specific_fifo)->thread;
+  else
+{
+  pi->start = &stuff->start;
+  pi->stop_thread = false;
+  pi->thread = new cygthread (thread_fifo, pi, "fifosel");
+  me->h = *pi->thread;
+  if (!me->h)
+   return 0;
+}
+  return 1;
+}
+
+static void
+fifo_cleanup (select_record *, select_stuff *stuff)
+{
+  select_fifo_info *pi = (select_fifo_info *) stuff->device_specific_fifo;
+  if (!pi)
+return;
+  if (pi->thread)
+{
+  pi->stop_thread = true;
+  pi->thread->detach ();
+}
+  delete pi;
+  stuff->device_specific_fifo = NULL;
+}
+
 select_record *
 fhandler_fifo::select_read (select_stuff *ss)
 {
-  if (!ss->device_specific_pipe
-  && (ss->device_specific_pipe = new sele

[PATCH fifo 5/8] Cygwin: FIFO: update clone and dup

2019-03-22 Thread Ken Brown
Deal with all clients.
---
 winsup/cygwin/fhandler.h   |  8 +---
 winsup/cygwin/fhandler_fifo.cc | 25 +
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index af5f500bf..0ebc44e0d 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1309,9 +1309,11 @@ public:
   fhandler_fifo *clone (cygheap_types malloc_type = HEAP_FHANDLER)
   {
 void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_fifo));
-fhandler_fifo *fh = new (ptr) fhandler_fifo (ptr);
-copyto (fh);
-return fh;
+fhandler_fifo *fhf = new (ptr) fhandler_fifo (ptr);
+copyto (fhf);
+for (int i = 0; i < nclients; i++)
+  fhf->client[i].fh = client[i].fh->fhandler_base::clone ();
+return fhf;
   }
 };
 
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 1dcb3b3df..c295c2393 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -816,6 +816,31 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
   __seterrno ();
   return -1;
 }
+  for (int i = 0; i < nclients; i++)
+{
+  if (!DuplicateHandle (GetCurrentProcess (), client[i].fh->get_handle (),
+   GetCurrentProcess (),
+   &fhf->client[i].fh->get_handle (),
+   0, true, DUPLICATE_SAME_ACCESS)
+ || !DuplicateHandle (GetCurrentProcess (), client[i].connect_evt,
+  GetCurrentProcess (),
+  &fhf->client[i].connect_evt,
+  0, true, DUPLICATE_SAME_ACCESS)
+ || !DuplicateHandle (GetCurrentProcess (), client[i].dummy_evt,
+  GetCurrentProcess (),
+  &fhf->client[i].dummy_evt,
+  0, true, DUPLICATE_SAME_ACCESS))
+   {
+ CloseHandle (fhf->read_ready);
+ CloseHandle (fhf->write_ready);
+ fhf->close ();
+ __seterrno ();
+ return -1;
+   }
+}
+  fhf->listen_client_thr = NULL;
+  fhf->lct_termination_evt = NULL;
+  fhf->fifo_client_unlock ();
   return 0;
 }
 
-- 
2.17.0



[PATCH fifo 6/8] Cygwin: FIFO: update fixup_after_fork

2019-03-22 Thread Ken Brown
Fixup each client.  Reset listen_client_thr and lct_termination_evt.
---
 winsup/cygwin/fhandler_fifo.cc | 9 +
 1 file changed, 9 insertions(+)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index c295c2393..7a592aa0d 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -850,6 +850,15 @@ fhandler_fifo::fixup_after_fork (HANDLE parent)
   fhandler_base::fixup_after_fork (parent);
   fork_fixup (parent, read_ready, "read_ready");
   fork_fixup (parent, write_ready, "write_ready");
+  for (int i = 0; i < nclients; i++)
+{
+  client[i].fh->fhandler_base::fixup_after_fork (parent);
+  fork_fixup (parent, client[i].connect_evt, "connect_evt");
+  fork_fixup (parent, client[i].dummy_evt, "dummy_evt");
+}
+  listen_client_thr = NULL;
+  lct_termination_evt = NULL;
+  fifo_client_unlock ();
 }
 
 void
-- 
2.17.0



[PATCH fifo 2/8] Cygwin: FIFO: allow multiple writers

2019-03-22 Thread Ken Brown
Introduce a 'fifo_client_handler' structure that can be used by a
reader to communicate with a writer using an instance of the named
pipe.  An fhandler_fifo opened for reading creates a thread that does
the following:

 - maintains a list of fifo_client_handlers
 - listens for_clients trying to connect
 - creates new pipe instances as needed so that there's always at
   least one available for connecting.

The pipe instances are initially created in blocking mode, but they
are set to be non-blocking after a connection is made.

fhandler_fifo::raw_read now loops through the connected clients and
reads from the first one that has data available.

New fhandler_fifo methods: add_client, listen_client,
listen_client_thread, check_listen_client_thread.

Replace the create_pipe method by create_pipe_instance, which allows
unlimited pipe instances.

New helper functions: create_event, set_pipe_non_blocking.
---
 winsup/cygwin/fhandler.h   |  31 ++-
 winsup/cygwin/fhandler_fifo.cc | 368 ++---
 2 files changed, 367 insertions(+), 32 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 57e97c277..e7c4af6a1 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1235,20 +1235,49 @@ public:
 };
 
 #define CYGWIN_FIFO_PIPE_NAME_LEN 47
+#define MAX_CLIENTS 64
+
+enum fifo_client_connect_state
+  {
+   fc_unknown,
+   fc_connecting,
+   fc_connected,
+   fc_invalid
+  };
+
+struct fifo_client_handler
+{
+  fhandler_base *fh;
+  fifo_client_connect_state state;
+  HANDLE connect_evt;
+  HANDLE dummy_evt;/* Never signaled. */
+  fifo_client_handler () : fh (NULL), state (fc_unknown), connect_evt (NULL),
+  dummy_evt (NULL) {}
+  int connect ();
+  int close ();
+};
 
 class fhandler_fifo: public fhandler_base
 {
   HANDLE read_ready;
   HANDLE write_ready;
+  HANDLE listen_client_thr;
+  HANDLE lct_termination_evt;
   UNICODE_STRING pipe_name;
   WCHAR pipe_name_buf[CYGWIN_FIFO_PIPE_NAME_LEN + 1];
+  fifo_client_handler client[MAX_CLIENTS];
+  int nclients, nconnected;
   bool __reg2 wait (HANDLE);
   NTSTATUS npfs_handle (HANDLE &);
-  HANDLE create_pipe ();
+  HANDLE create_pipe_instance (bool);
   NTSTATUS open_pipe ();
+  int disconnect_and_reconnect (int);
+  int add_client ();
+  bool listen_client ();
 public:
   fhandler_fifo ();
   PUNICODE_STRING get_pipe_name ();
+  DWORD listen_client_thread ();
   int open (int, mode_t);
   off_t lseek (off_t offset, int whence);
   int close ();
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index cb269e344..e91e88050 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -31,8 +31,9 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
   || _s == STATUS_PIPE_EMPTY; })
 
 fhandler_fifo::fhandler_fifo ():
-  fhandler_base (),
-  read_ready (NULL), write_ready (NULL)
+  fhandler_base (), read_ready (NULL), write_ready (NULL),
+  listen_client_thr (NULL), lct_termination_evt (NULL), nclients (0),
+  nconnected (0)
 {
   pipe_name_buf[0] = L'\0';
   need_fork_fixup (true);
@@ -78,6 +79,94 @@ fhandler_fifo::arm (HANDLE h)
   return res;
 }
 
+static HANDLE
+create_event ()
+{
+  NTSTATUS status;
+  OBJECT_ATTRIBUTES attr;
+  HANDLE evt = NULL;
+
+  InitializeObjectAttributes (&attr, NULL, 0, NULL, NULL);
+  status = NtCreateEvent (&evt, EVENT_ALL_ACCESS, &attr,
+ NotificationEvent, FALSE);
+  if (!NT_SUCCESS (status))
+__seterrno_from_nt_status (status);
+  return evt;
+}
+
+
+static void
+set_pipe_non_blocking (HANDLE ph, bool nonblocking)
+{
+  NTSTATUS status;
+  IO_STATUS_BLOCK io;
+  FILE_PIPE_INFORMATION fpi;
+
+  fpi.ReadMode = FILE_PIPE_MESSAGE_MODE;
+  fpi.CompletionMode = nonblocking ? FILE_PIPE_COMPLETE_OPERATION
+: FILE_PIPE_QUEUE_OPERATION;
+  status = NtSetInformationFile (ph, &io, &fpi, sizeof fpi,
+FilePipeInformation);
+  if (!NT_SUCCESS (status))
+debug_printf ("NtSetInformationFile(FilePipeInformation): %y", status);
+}
+
+/* The pipe instance is always in blocking mode when this is called. */
+int
+fifo_client_handler::connect ()
+{
+  NTSTATUS status;
+  IO_STATUS_BLOCK io;
+
+  if (connect_evt)
+ResetEvent (connect_evt);
+  else if (!(connect_evt = create_event ()))
+return -1;
+  status = NtFsControlFile (fh->get_handle (), connect_evt, NULL, NULL, &io,
+   FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
+  switch (status)
+{
+case STATUS_PENDING:
+case STATUS_PIPE_LISTENING:
+  state = fc_connecting;
+  break;
+case STATUS_PIPE_CONNECTED:
+  state = fc_connected;
+  set_pipe_non_blocking (fh->get_handle (), true);
+  break;
+default:
+  __seterrno_from_nt_status (status);
+  return -1;
+}
+  return 0;
+}
+
+int
+fhandler_fifo::disconnect_and_reconnect (int i)
+{
+  NTSTATUS status;
+  IO_STATUS_BLOCK io;
+  HANDLE 

[PATCH fifo 7/8] Cygwin: FIFO: update set_close_on_exec

2019-03-22 Thread Ken Brown
Deal with each client.
---
 winsup/cygwin/fhandler_fifo.cc | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 7a592aa0d..2c20444c6 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -867,4 +867,10 @@ fhandler_fifo::set_close_on_exec (bool val)
   fhandler_base::set_close_on_exec (val);
   set_no_inheritance (read_ready, val);
   set_no_inheritance (write_ready, val);
+  for (int i = 0; i < nclients; i++)
+{
+  client[i].fh->fhandler_base::set_close_on_exec (val);
+  set_no_inheritance (client[i].connect_evt, val);
+  set_no_inheritance (client[i].dummy_evt, val);
+}
 }
-- 
2.17.0



[PATCH fifo 4/8] Cygwin: FIFO: improve EOF detection

2019-03-22 Thread Ken Brown
Add a hit_eof method that tries to detect whether any clients are
connected.  Before concluding that there are none, it gives the
listen_client thread time to update the client data.
---
 winsup/cygwin/fhandler.h   |  1 +
 winsup/cygwin/fhandler_fifo.cc | 21 -
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 997dc0b6d..af5f500bf 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1277,6 +1277,7 @@ class fhandler_fifo: public fhandler_base
   bool listen_client ();
 public:
   fhandler_fifo ();
+  bool hit_eof ();
   PUNICODE_STRING get_pipe_name ();
   DWORD listen_client_thread ();
   void fifo_client_lock () { _fifo_client_lock.lock (); }
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index b0016ee90..1dcb3b3df 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -654,6 +654,25 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
   return ret;
 }
 
+/* A FIFO open for reading is at EOF if no process has it open for
+   writing.  We test this by checking nconnected.  But we must take
+   account of the possible delay from the time of connection to the
+   time the connection is recorded by the listen_client thread. */
+bool
+fhandler_fifo::hit_eof ()
+{
+  fifo_client_lock ();
+  bool eof = (nconnected == 0);
+  fifo_client_unlock ();
+  if (eof)
+{
+  /* Give the listen_client thread time to catch up, then recheck. */
+  Sleep (1);
+  eof = (nconnected == 0);
+}
+  return eof;
+}
+
 void __reg3
 fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 {
@@ -665,7 +684,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
 
   while (1)
 {
-  if (nconnected == 0) /* EOF */
+  if (hit_eof ())
{
  len = 0;
  return;
-- 
2.17.0



Re: [PATCH fifo 0/8] Allow a FIFO to have multiple writers

2019-03-23 Thread Ken Brown
On 3/23/2019 4:02 PM, Corinna Vinschen wrote:
> Your patch series looks really good.  For now I pushed it into the
> topic/fifo branch as you suggested.

Thanks.

> Just be aware that it won't get much 3rd party testing this way, so as
> soon as you feel more confident, let's move it into master.  At that
> time I'll create a Cygwin 3.0.y branch for bugfix releases, but the
> snapshots will continue to be created from master so we get at least
> *some* folks testing it.

Sounds good.  It shouldn't be too long.

> A big thank you already!
> 
> Oh, there's obviously a downside to this, too:  You'll have to create
> a release note for this change at one point ;)

Oh yeah, I forgot about that.  No problem.

Ken


[PATCH fifo 0/2] Add support for duplex FIFOs

2019-03-25 Thread Ken Brown
The second patch in this series enables opening a FIFO with O_RDWR
access.  The underlying Windows named pipe is creted with duplex
access, and its handle is made the I/O handle of the first client.

While testing this, I had some mysterious crashes, which are fixed by
the first patch.

I tested the patch in two ways.

First, I went back to Kerrisk's server/client programs cited in
https://cygwin.com/ml/cygwin/2015-03/msg00047.html.  The server
program opens a FIFO twice, once with O_RDONLY access and once with
O_WRONLY access.  The fd from the second call is never used; the
purpose of that call is simply to make sure that attempts to read from
the FIFO will never indicate EOF.  I removed the second call and
instead opened the FIFO only once, with O_RDWR access.  The
server/client programs still worked as expected.

The second test was the following sequence of commands in a bash
shell:

$ mkfifo foo

$ exec 7<>foo

$ echo blah > foo

$ read bar <&7

$ echo $bar
blah

Ken

Ken Brown (2):
  Cygwin: FIFO: avoid crashes when cloning a client
  Cygwin: FIFO: add support for the duplex case

 winsup/cygwin/fhandler.h   |  7 ++-
 winsup/cygwin/fhandler_fifo.cc | 79 +-
 2 files changed, 74 insertions(+), 12 deletions(-)

-- 
2.17.0



[PATCH fifo 1/2] Cygwin: FIFO: avoid crashes when cloning a client

2019-03-25 Thread Ken Brown
fhandler_fifo::clone called fhandler_base::clone on each client
fhandler.  But those fhandlers are actually fhandler_fifo objects, so
when fhandler_base::clone calls copyto, it's actually
fhandler_fifo::copyto that gets called.  This can lead to mysterious
crashes.

Fix this by simply calling clone (which translates to
fhandler_fifo::clone) on each client fhandler.
---
 winsup/cygwin/fhandler.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index f6982f0ba..ef34f9c40 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1316,7 +1316,7 @@ public:
 fhandler_fifo *fhf = new (ptr) fhandler_fifo (ptr);
 copyto (fhf);
 for (int i = 0; i < nclients; i++)
-  fhf->client[i].fh = client[i].fh->fhandler_base::clone ();
+  fhf->client[i].fh = client[i].fh->clone ();
 return fhf;
   }
 };
-- 
2.17.0



[PATCH fifo 2/2] Cygwin: FIFO: add support for the duplex case

2019-03-25 Thread Ken Brown
If a FIFO is opened with O_RDWR access, create the pipe with
read/write access, and make the first client have the handle of that
pipe as its I/O handle.

Adjust fhandler_fifo::raw_read to account for the result of trying to
read from that client if there's no data.
---
 winsup/cygwin/fhandler.h   |  5 +++
 winsup/cygwin/fhandler_fifo.cc | 79 +-
 2 files changed, 73 insertions(+), 11 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index ef34f9c40..3398cc625 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1253,6 +1253,10 @@ struct fifo_client_handler
   HANDLE dummy_evt;/* Never signaled. */
   fifo_client_handler () : fh (NULL), state (fc_unknown), connect_evt (NULL),
   dummy_evt (NULL) {}
+  fifo_client_handler (fhandler_base *_fh, fifo_client_connect_state _state,
+  HANDLE _connect_evt, HANDLE _dummy_evt)
+: fh (_fh), state (_state), connect_evt (_connect_evt),
+  dummy_evt (_dummy_evt) {}
   int connect ();
   int close ();
 };
@@ -1268,6 +1272,7 @@ class fhandler_fifo: public fhandler_base
   fifo_client_handler client[MAX_CLIENTS];
   int nclients, nconnected;
   af_unix_spinlock_t _fifo_client_lock;
+  bool _duplexer;
   bool __reg2 wait (HANDLE);
   NTSTATUS npfs_handle (HANDLE &);
   HANDLE create_pipe_instance (bool);
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 2c20444c6..7847cca82 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -33,7 +33,7 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
 fhandler_fifo::fhandler_fifo ():
   fhandler_base (), read_ready (NULL), write_ready (NULL),
   listen_client_thr (NULL), lct_termination_evt (NULL), nclients (0),
-  nconnected (0)
+  nconnected (0), _duplexer (false)
 {
   pipe_name_buf[0] = L'\0';
   need_fork_fixup (true);
@@ -224,6 +224,8 @@ fhandler_fifo::create_pipe_instance (bool first)
 }
   access = GENERIC_READ | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES
 | SYNCHRONIZE;
+  if (first && _duplexer)
+access |= GENERIC_WRITE;
   sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
   hattr = OBJ_INHERIT;
   if (first)
@@ -437,7 +439,7 @@ fhandler_fifo::open (int flags, mode_t)
 case O_RDWR:
   reader = true;
   writer = false;
-  duplexer = true;
+  duplexer = _duplexer = true;
   break;
 default:
   set_errno (EINVAL);
@@ -447,7 +449,7 @@ fhandler_fifo::open (int flags, mode_t)
 
   debug_only_printf ("reader %d, writer %d, duplexer %d", reader, writer, 
duplexer);
   set_flags (flags);
-  if (reader)
+  if (reader && !duplexer)
 nohandle (true);
 
   /* Create control events for this named pipe */
@@ -472,6 +474,48 @@ fhandler_fifo::open (int flags, mode_t)
   goto out;
 }
 
+  /* If we're a duplexer, create the pipe and the first client. */
+  if (duplexer)
+{
+  HANDLE ph, connect_evt, dummy_evt;
+  fhandler_base *fh;
+
+  ph = create_pipe_instance (true);
+  if (!ph)
+   {
+ res = error_errno_set;
+ goto out;
+   }
+  set_io_handle (ph);
+  set_pipe_non_blocking (ph, true);
+  if (!(fh = build_fh_dev (dev (
+   {
+ set_errno (EMFILE);
+ res = error_errno_set;
+ goto out;
+   }
+  fh->set_io_handle (ph);
+  fh->set_flags (flags);
+  if (!(connect_evt = create_event ()))
+   {
+ res = error_errno_set;
+ fh->close ();
+ delete fh;
+ goto out;
+   }
+  if (!(dummy_evt = create_event ()))
+   {
+ res = error_errno_set;
+ delete fh;
+ fh->close ();
+ CloseHandle (connect_evt);
+ goto out;
+   }
+  client[0] = fifo_client_handler (fh, fc_connected, connect_evt,
+  dummy_evt);
+  nconnected = nclients = 1;
+}
+
   /* If we're reading, start the listen_client thread (which should
  signal read_ready), and wait for a writer. */
   if (reader)
@@ -482,8 +526,8 @@ fhandler_fifo::open (int flags, mode_t)
  res = error_errno_set;
  goto out;
}
-  /* Wait for the listen_client thread to create the pipe and
-signal read_ready.  This should be quick.  */
+  /* Wait for the listen_client thread to signal read_ready.  This
+should be quick.  */
   HANDLE w[2] = { listen_client_thr, read_ready };
   switch (WaitForMultipleObjects (2, w, FALSE, INFINITE))
{
@@ -703,12 +747,25 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
fifo_client_unlock ();
return;
  }
-   else if (nread < 0 && GetLastError () != ERROR_NO_DATA)
- {
-   fifo_client_unlock ();
-   goto errout;
- }
-   else if (nread == 0) /* Client has disconnected. */
+   /* In the duplex case w

Re: [PATCH fifo 0/2] Add support for duplex FIFOs

2019-03-26 Thread Ken Brown
Hi Corinna,

On 3/26/2019 4:36 AM, Corinna Vinschen wrote:
> Hi Ken,
> 
> On Mar 25 23:06, Ken Brown wrote:
>> The second patch in this series enables opening a FIFO with O_RDWR
>> access.  The underlying Windows named pipe is creted with duplex
>> access, and its handle is made the I/O handle of the first client.
>>
>> While testing this, I had some mysterious crashes, which are fixed by
>> the first patch.
> 
> I rebased the topic/fifo branch on top of master and force-pushed with
> your patches.  Make sure to reset your working tree to origin/topic/fifo
> and add any further patches on top.

I'm comfortable now with merging topic/fifo into master.  I've tested the new 
select and fork code [*], and they seem to work as expected.  That was the last 
thing holding me up.

As soon as the merge is done, I'll send a patch with release notes.

Ken

[*] For the record, I'm attaching the two test programs I used.  In each case I 
ran the program in one terminal and typed "echo blah > /tmp/myfifo" in a second 
terminal.
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int
main ()
{
  int fd;
  ssize_t nbytes;
  char buf[5];

  if (mkfifo ("/tmp/myfifo", S_IRUSR | S_IWUSR | S_IWGRP) < 0
  && errno != EEXIST)
{
  perror ("mkfifo");
  exit (-1);
}

  if ((fd = open ("/tmp/myfifo", O_RDWR)) < 0)
{
  perror ("open");
  exit (-1);
}

  switch (fork ())
{
case -1:
  perror ("fork");
  exit (-1);
case 0: /* Child. */
  nbytes = read (fd, buf, 4);
  if (nbytes != 4)
{
  perror ("read");
  exit (-1);
}
  buf[4] = '\0';
  printf ("child read %d bytes: %s\n", nbytes, buf);
  if (close (fd) < 0)
{
  perror ("child close");
  exit (-1);
}
  exit (0);
default:/* Parent. */
  if (close (fd) < 0)
{
  perror ("parent close");
  exit (-1);
}
  printf ("parent waiting for child to read\n");
  wait (NULL);
  break;
}
}

  
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int
main ()
{
  int fd, nfds;
  fd_set readfds;
  ssize_t nbytes;
  char buf[5];

  if (mkfifo ("/tmp/myfifo", S_IRUSR | S_IWUSR | S_IWGRP) < 0
  && errno != EEXIST)
{
  perror ("mkfifo");
  exit (-1);
}

  if ((fd = open ("/tmp/myfifo", O_RDONLY)) < 0)
{
  perror ("open");
  exit (-1);
}

  FD_ZERO (&readfds);
  FD_SET (fd, &readfds);

  if ((nfds = select (fd + 1, &readfds, NULL, NULL, NULL)) < 0)
{
  perror ("select");
  exit (-1);
}

  if (FD_ISSET (fd, &readfds))
printf ("/tmp/myfifo is ready for reading\n");
  else
printf ("something's wrong\n");
  nbytes = read (fd, buf, 4);
  if (nbytes != 4)
{
  perror ("read");
  exit (-1);
}
  buf[4] = '\0';
  printf ("read %d bytes: %s\n", nbytes, buf);
  if (close (fd) < 0)
{
  perror ("close");
  exit (-1);
}
}


[PATCH] Cygwin: document the recent FIFO changes

2019-03-27 Thread Ken Brown
---
 winsup/cygwin/release/3.1.0 | 14 ++
 winsup/doc/new-features.xml | 12 
 2 files changed, 26 insertions(+)
 create mode 100644 winsup/cygwin/release/3.1.0

diff --git a/winsup/cygwin/release/3.1.0 b/winsup/cygwin/release/3.1.0
new file mode 100644
index 0..1f017bfd1
--- /dev/null
+++ b/winsup/cygwin/release/3.1.0
@@ -0,0 +1,14 @@
+What's new:
+---
+
+
+What changed:
+-
+
+- FIFOs can now be opened multiple times for writing.
+  Addresses: https://cygwin.com/ml/cygwin/2015-03/msg00047.html
+ https://cygwin.com/ml/cygwin/2015-12/msg00311.html
+
+
+Bug Fixes
+-
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index e14fbb1e8..c87601e9d 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -4,6 +4,18 @@
 
 What's new and what changed in Cygwin
 
+What's new and what changed in 3.1
+
+
+
+
+FIFOs can now be opened multiple times for writing.
+
+
+
+
+
+
 What's new and what changed in 3.0
 
 
-- 
2.17.0



[PATCH] Cygwin: FIFO: implement clear_readahead

2019-03-27 Thread Ken Brown
Make fhandler_base::clear_readahead virtual, and implement
fhandler_fifo::clear_readahead.  This is called by
dtable::fixup_after_exec; it clears the readahead in each client.
---
 winsup/cygwin/fhandler.h | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 3398cc625..21fec9e38 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -444,7 +444,7 @@ public:
 return dev ().native ();
   }
   virtual bg_check_types bg_check (int, bool = false) {return bg_ok;}
-  void clear_readahead ()
+  virtual void clear_readahead ()
   {
 raixput = raixget = ralen = rabuflen = 0;
 rabuf = NULL;
@@ -1302,6 +1302,12 @@ public:
   bool arm (HANDLE h);
   void fixup_after_fork (HANDLE);
   int __reg2 fstatvfs (struct statvfs *buf);
+  void clear_readahead ()
+  {
+fhandler_base::clear_readahead ();
+for (int i = 0; i < nclients; i++)
+  client[i].fh->clear_readahead ();
+  }
   select_record *select_read (select_stuff *);
   select_record *select_write (select_stuff *);
   select_record *select_except (select_stuff *);
-- 
2.17.0



Re: [PATCH fifo 0/2] Add support for duplex FIFOs

2019-03-28 Thread Ken Brown
On 3/28/2019 4:13 PM, Corinna Vinschen wrote:
> On Mar 28 19:01, Achim Gratz wrote:
>> Corinna Vinschen writes:
>>> Done.  I also pushed out new dev snapshots.
>>
>> No good deed goes unpunished…
>>
>> Whith the 20190327 snapshot our main data processing application is
>> broken.  It looks like it should almost work, it doesn't crash or
>> anything, but the pipe that delivers a script+data into gnuplot seems to
>> either skip or overwrite data and then gnuplot bails with a syntax
>> error.  Depending on exactly which data I try to plot I get the first or
>> first few plots out through the whole processing pipe (that ends in a
>> PDF file), albeit sometimes with incomplete data.  Doing each of the
>> steps manually (i.e. writing the gnuplot script into a file, then feed
>> that into gnuplot, then the output from gnuplot inth ghostscript) does
>> work correctly.  I have not yet been able to reduce this down to some
>> simpler test case, so I had to roll back to the previous snapshot.  I
>> still have it installed on the development system, though.
> 
> I'm pretty sure Ken would be happy about an STC.

Yes, please.  Barring that, is there any chance I could see the relevant code, 
or at least enough of it so that I can see how FIFOs are being used?

Thanks, and thanks for testing.

Ken


Re: [PATCH fifo 0/2] Add support for duplex FIFOs

2019-03-29 Thread Ken Brown
On 3/29/2019 3:17 AM, Achim Gratz wrote:
> Ken Brown writes:
>>> I'm pretty sure Ken would be happy about an STC.
>>
>> Yes, please.  Barring that, is there any chance I could see the relevant 
>> code,
>> or at least enough of it so that I can see how FIFOs are being used?
> 
> Well, I'm trying -- but got nothing so far.  As the individual FIFO seem
> to work and the error happens pretty early, I think it has something to
> do with either switching between different FIFO (which the original code
> does) or some race between fill and drain, possibly around a buffer
> boundary (in my limited testing it always seemed to happen in the same
> place for the same data).

I found a bug in my fhandler_fifo::raw_write code that could explain the 
problem.  The call to NtWriteFile in that function always returns immediately 
because the Windows named pipe underlying the FIFO is non-blocking.  If it 
can't 
write because the pipe buffer is full, raw_write returns -1 with error EAGAIN. 
That's wrong if the FIFO was opened in blocking mode.

I'll have to think about how to best handle this.  I think I might be able to 
imitate what's done in fhandler_socket_unix::sendmsg in the topic/af_unix 
branch.

Ken


Re: [PATCH fifo 2/2] Cygwin: FIFO: add support for the duplex case

2019-03-30 Thread Ken Brown
Hi Takashi,

On 3/30/2019 9:30 AM, Takashi Yano wrote:
> Hi Ken,
> 
> Do these patches enable to open FIFO multiple times with O_RDWR?
> mc (midnight commander) tries to open FIFO twice with O_RDWR if
> SHELL=/bin/tcsh, but fails.
> https://cygwin.com/ml/cygwin/2017-03/msg00188.html

No, I'm sorry.  At the moment, a FIFO can only be opened once for reading.  I 
plan to work on this next, but first I have some bugs to fix.

Ken


Re: [PATCH fifo 0/2] Add support for duplex FIFOs

2019-04-03 Thread Ken Brown
On 4/3/2019 8:33 AM, Achim Gratz wrote:
> Achim Gratz writes:
>> OK, a bit more info: The whole thing runs from a perl script (actually a
>> module) that opens pipes to gnuplot and ghostscript.  This code is
>> _really_ old and has seen a lot of Cygwin releases, so it has options to
>> either use temporary files, named pipes aka FIFO or direct pipes.  Using
>> temporary files serializes the execution and using a pipe chain is
>> _really_ slow (like a hundred times, which is mostly tied up in system
>> for a reason that I don't understand), so using FIFO is the default.
>> Your new FIFO code increases the system time by about a factor of 10 in
>> my tests, btw.
> 
> So I've finalöly got around to fixing the pipe performance problem by
> fooling the programs involved to think they are using files: have them
> reading from /proc/self/fd/0 and writing to /proc/self/fd/1 gives me the
> same performance as using a named FIFO.
> 
> Incidentally, that workaround still works when I switch to the 20190402
> snapshot, while named FIFO fails as with the older snapshot (as
> expected), so that seems to take a different code path.  Maybe that
> helps in finding the problem?

Thanks.

In the meantime, I've fixed the raw_write bug that I mentioned in an earlier 
post, along with some other bugs I found.  I want to do a little more testing 
before I send the patches.

Ken


[PATCH 03/14] Cygwin: FIFO: remember the type of the fhandler

2019-04-14 Thread Ken Brown
Add data members 'reader', 'writer', and 'duplexer' to the
fhandler_fifo class.  Set them in fhandler_fifo::open.  ('duplexer'
replaces the previous '_duplexer'.)

This will be useful in later commits.
---
 winsup/cygwin/fhandler.h   |  2 +-
 winsup/cygwin/fhandler_fifo.cc | 14 --
 2 files changed, 5 insertions(+), 11 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 2898db4df..59d9dad16 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1272,7 +1272,7 @@ class fhandler_fifo: public fhandler_base
   fifo_client_handler fc_handler[MAX_CLIENTS];
   int nhandlers, nconnected;
   af_unix_spinlock_t _fifo_client_lock;
-  bool _duplexer;
+  bool reader, writer, duplexer;
   bool __reg2 wait (HANDLE);
   NTSTATUS npfs_handle (HANDLE &);
   HANDLE create_pipe_instance (bool);
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 70551ebac..258c3cf8a 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -33,7 +33,7 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
 fhandler_fifo::fhandler_fifo ():
   fhandler_base (), read_ready (NULL), write_ready (NULL),
   listen_client_thr (NULL), lct_termination_evt (NULL), nhandlers (0),
-  nconnected (0), _duplexer (false)
+  nconnected (0), reader (false), writer (false), duplexer (false)
 {
   pipe_name_buf[0] = L'\0';
   need_fork_fixup (true);
@@ -224,7 +224,7 @@ fhandler_fifo::create_pipe_instance (bool first)
 }
   access = GENERIC_READ | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES
 | SYNCHRONIZE;
-  if (first && _duplexer)
+  if (first && duplexer)
 access |= GENERIC_WRITE;
   sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
   hattr = OBJ_INHERIT;
@@ -421,25 +421,19 @@ fhandler_fifo::open (int flags, mode_t)
error_errno_set,
error_set_errno
   } res;
-  bool reader, writer, duplexer;
 
   /* Determine what we're doing with this fhandler: reading, writing, both */
   switch (flags & O_ACCMODE)
 {
 case O_RDONLY:
   reader = true;
-  writer = false;
-  duplexer = false;
   break;
 case O_WRONLY:
   writer = true;
-  reader = false;
-  duplexer = false;
   break;
 case O_RDWR:
   reader = true;
-  writer = false;
-  duplexer = _duplexer = true;
+  duplexer = true;
   break;
 default:
   set_errno (EINVAL);
@@ -769,7 +763,7 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
  fifo_client_unlock ();
  goto errout;
}
-   else if (nread == 0 && (!_duplexer || i > 0))
+   else if (nread == 0 && (!duplexer || i > 0))
  /* Client has disconnected. */
  {
fc_handler[i].state = fc_invalid;
-- 
2.17.0



[PATCH 00/14] FIFO bug fixes and code simplifications

2019-04-14 Thread Ken Brown
Ken Brown (14):
  Cygwin: FIFO: rename client[] to fc_handler[]
  Cygwin: FIFO: hit_eof: add a call to fifo_client_lock
  Cygwin: FIFO: remember the type of the fhandler
  Cygwin: FIFO: fix a thinko in listen_client_thread
  Cygwin: FIFO: fix the error checking in raw_read
  Cygwin: check for STATUS_PENDING in fhandler_base::raw_read
  Cygwin: FIFO: code simplification: don't overload get_handle
  Cygwin: FIFO: fix fifo_client_handler::close
  Cygwin: FIFO: fix the use of the read_ready event
  Cygwin: FIFO: use a retry loop when opening a writer
  Cygwin: FIFO: fix clone
  Cygwin: FIFO: start the listen_client thread when duping a reader
  Cygwin: FIFO: improve raw_write
  Cygwin: FIFO: fix and simplify listen_client_thread

 winsup/cygwin/fhandler.cc  |  14 +-
 winsup/cygwin/fhandler.h   |  43 +--
 winsup/cygwin/fhandler_fifo.cc | 580 +
 winsup/cygwin/select.cc|   4 +-
 4 files changed, 342 insertions(+), 299 deletions(-)

-- 
2.17.0



[PATCH 04/14] Cygwin: FIFO: fix a thinko in listen_client_thread

2019-04-14 Thread Ken Brown
---
 winsup/cygwin/fhandler_fifo.cc | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 258c3cf8a..764420ffd 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -362,7 +362,10 @@ fhandler_fifo::listen_client_thread ()
fifo_client_unlock ();
goto errout;
  }
-   /* Fall through. */
+   else
+ /* Recheck fc_handler[i].state. */
+ i--;
+   break;
  case fc_connected:
w[i] = fc_handler[i].dummy_evt;
break;
-- 
2.17.0



[PATCH 11/14] Cygwin: FIFO: fix clone

2019-04-14 Thread Ken Brown
After copyto is called, make the new fhandler's pipe_name point to the
new fhandler's pipe_name_buf, which is a *copy* of the old fhandler's
pipe_name_buf.  Previously, get_pipe_name would return the wrong
result after a clone/dup, causing create_pipe_instance and open_pipe
to fail.

Also, stop the listen_client thread when cloning.  Otherwise the
thread can keep accepting connections that the cloned fhandler won't
know about.

Do this via a new method fhandler_fifo::stop_listen_client, extracted
from fhandler_fifo::close.
---
 winsup/cygwin/fhandler.h   |  6 ++
 winsup/cygwin/fhandler_fifo.cc | 20 +++-
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 1e26c651f..aea02c2b3 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1280,6 +1280,7 @@ class fhandler_fifo: public fhandler_base
   int disconnect_and_reconnect (int);
   int add_client_handler ();
   bool listen_client ();
+  int stop_listen_client ();
 public:
   fhandler_fifo ();
   bool hit_eof ();
@@ -1326,7 +1327,12 @@ public:
   {
 void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_fifo));
 fhandler_fifo *fhf = new (ptr) fhandler_fifo (ptr);
+/* We don't want our client list to change any more. */
+stop_listen_client ();
 copyto (fhf);
+/* fhf->pipe_name_buf is a *copy* of this->pipe_name_buf, but
+   fhf->pipe_name.Buffer == this->pipe_name_buf. */
+fhf->pipe_name.Buffer = fhf->pipe_name_buf;
 for (int i = 0; i < nhandlers; i++)
   fhf->fc_handler[i].fh = fc_handler[i].fh->clone ();
 return fhf;
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index d4d2b3883..a3ecbeb4a 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -812,9 +812,9 @@ fifo_client_handler::close ()
 }
 
 int
-fhandler_fifo::close ()
+fhandler_fifo::stop_listen_client ()
 {
-  int res = 0;
+  int ret = 0;
   HANDLE evt = InterlockedExchangePointer (&lct_termination_evt, NULL);
   HANDLE thr = InterlockedExchangePointer (&listen_client_thr, NULL);
   if (thr)
@@ -825,19 +825,29 @@ fhandler_fifo::close ()
   DWORD err;
   GetExitCodeThread (thr, &err);
   if (err)
-   debug_printf ("listen_client_thread exited with code %d", err);
+   {
+ ret = -1;
+ debug_printf ("listen_client_thread exited with error, %E");
+   }
   CloseHandle (thr);
 }
   if (evt)
 CloseHandle (evt);
+  return ret;
+}
+
+int
+fhandler_fifo::close ()
+{
+  int ret = stop_listen_client ();
   if (read_ready)
 CloseHandle (read_ready);
   if (write_ready)
 CloseHandle (write_ready);
   for (int i = 0; i < nhandlers; i++)
 if (fc_handler[i].close () < 0)
-  res = -1;
-  return fhandler_base::close () || res;
+  ret = -1;
+  return fhandler_base::close () || ret;
 }
 
 int
-- 
2.17.0



[PATCH 13/14] Cygwin: FIFO: improve raw_write

2019-04-14 Thread Ken Brown
Don't set the write end of the pipe to non-blocking mode if the FIFO
is opened in blocking mode.

In fhandler_fifo::raw_write in blocking mode, wait for the write to
complete rather than returning -1 with EAGAIN.

If the amount to write is large, write in smaller chunks (of size
determined by a new data member max_atomic_write), as in
fhandler_base_overlapped.
---
 winsup/cygwin/fhandler.h   |  1 +
 winsup/cygwin/fhandler_fifo.cc | 96 +++---
 2 files changed, 79 insertions(+), 18 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index aea02c2b3..fd205a6db 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1273,6 +1273,7 @@ class fhandler_fifo: public fhandler_base
   int nhandlers, nconnected;
   af_unix_spinlock_t _fifo_client_lock;
   bool reader, writer, duplexer;
+  size_t max_atomic_write;
   bool __reg2 wait (HANDLE);
   NTSTATUS npfs_handle (HANDLE &);
   HANDLE create_pipe_instance (bool);
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index fe4c67bdf..ce078d74d 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -22,6 +22,9 @@
 #include "ntdll.h"
 #include "cygwait.h"
 
+#define STATUS_THREAD_SIGNALED ((NTSTATUS)0xE001)
+#define STATUS_THREAD_CANCELED ((NTSTATUS)0xE002)
+
 /* This is only to be used for writers.  When reading,
 STATUS_PIPE_EMPTY simply means there's no data to be read. */
 #define STATUS_PIPE_IS_CLOSED(status)  \
@@ -39,7 +42,8 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
 fhandler_fifo::fhandler_fifo ():
   fhandler_base (), read_ready (NULL), write_ready (NULL),
   listen_client_thr (NULL), lct_termination_evt (NULL), nhandlers (0),
-  nconnected (0), reader (false), writer (false), duplexer (false)
+  nconnected (0), reader (false), writer (false), duplexer (false),
+  max_atomic_write (DEFAULT_PIPEBUFSIZE)
 {
   pipe_name_buf[0] = L'\0';
   need_fork_fixup (true);
@@ -559,7 +563,7 @@ fhandler_fifo::open (int flags, mode_t)
  NTSTATUS status = open_pipe ();
  if (NT_SUCCESS (status))
{
- set_pipe_non_blocking (get_handle (), true);
+ set_pipe_non_blocking (get_handle (), flags & O_NONBLOCK);
  if (!arm (write_ready))
res = error_set_errno;
  else
@@ -661,28 +665,84 @@ ssize_t __reg3
 fhandler_fifo::raw_write (const void *ptr, size_t len)
 {
   ssize_t ret = -1;
+  size_t nbytes = 0, chunk;
   NTSTATUS status;
   IO_STATUS_BLOCK io;
+  HANDLE evt = NULL;
 
-  status = NtWriteFile (get_handle (), NULL, NULL, NULL, &io,
-   (PVOID) ptr, len, NULL, NULL);
-  if (NT_SUCCESS (status))
+  if (len <= max_atomic_write)
+chunk = len;
+  else if (is_nonblocking ())
+chunk = len = max_atomic_write;
+  else
+chunk = max_atomic_write;
+
+  /* Create a wait event if the FIFO is in blocking mode. */
+  if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
+return -1;
+
+  /* Write in chunks, accumulating a total.  If there's an error, just
+ return the accumulated total unless the first write fails, in
+ which case return -1. */
+  while (nbytes < len)
 {
-  /* NtWriteFile returns success with # of bytes written == 0 in
-case writing on a non-blocking pipe fails if the pipe buffer
-is full. */
-  if (io.Information == 0)
-   set_errno (EAGAIN);
+  ULONG_PTR nbytes_now = 0;
+  size_t left = len - nbytes;
+  size_t len1;
+  if (left > chunk)
+   len1 = chunk;
   else
-   ret = io.Information;
-}
-  else if (STATUS_PIPE_IS_CLOSED (status))
-{
-  set_errno (EPIPE);
-  raise (SIGPIPE);
+   len1 = left;
+  nbytes_now = 0;
+  status = NtWriteFile (get_handle (), evt, NULL, NULL, &io,
+   (PVOID) ptr, len1, NULL, NULL);
+  if (evt && status == STATUS_PENDING)
+   {
+ DWORD waitret = cygwait (evt, cw_infinite, cw_cancel | cw_sig_eintr);
+ switch (waitret)
+   {
+   case WAIT_OBJECT_0:
+ status = io.Status;
+ break;
+   case WAIT_SIGNALED:
+ status = STATUS_THREAD_SIGNALED;
+ break;
+   case WAIT_CANCELED:
+ status = STATUS_THREAD_CANCELED;
+ break;
+   default:
+ break;
+   }
+   }
+  if (NT_SUCCESS (status))
+   {
+ nbytes_now = io.Information;
+ /* NtWriteFile returns success with # of bytes written == 0
+if writing on a non-blocking pipe fails because the pipe
+buffer doesn't have sufficient space. */
+ if (nbytes_now == 0)
+   set_errno (EAGAIN);
+ ptr = ((char *) ptr) + chunk;
+ nbytes += nbytes_now;
+   }
+  else if (STATUS_PIPE_IS_CLOSED (status))
+   {
+ set_errno (EPIPE);
+ raise (SIGPIPE);
+ 

[PATCH 07/14] Cygwin: FIFO: code simplification: don't overload get_handle

2019-04-14 Thread Ken Brown
Rename fhandler_fifo::get_handle(int) to get_fc_handle(int), and
remove fhandler_fifo::get_handle(void).
---
 winsup/cygwin/fhandler.h | 7 ---
 winsup/cygwin/select.cc  | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 59d9dad16..1e26c651f 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1284,9 +1284,10 @@ public:
   fhandler_fifo ();
   bool hit_eof ();
   int get_nhandlers () const { return nhandlers; }
-  HANDLE& get_handle () { return fhandler_base::get_handle (); }
-  HANDLE get_handle (int i) const { return fc_handler[i].fh->get_handle (); }
-  bool is_connected (int i) const { return fc_handler[i].state == 
fc_connected; }
+  HANDLE get_fc_handle (int i) const
+  { return fc_handler[i].fh->get_handle (); }
+  bool is_connected (int i) const
+  { return fc_handler[i].state == fc_connected; }
   PUNICODE_STRING get_pipe_name ();
   DWORD listen_client_thread ();
   void fifo_client_lock () { _fifo_client_lock.lock (); }
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index d257cc4ed..9cf892801 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -875,7 +875,7 @@ peek_fifo (select_record *s, bool from_select)
   for (int i = 0; i < fh->get_nhandlers (); i++)
if (fh->is_connected (i))
  {
-   int n = pipe_data_available (s->fd, fh, fh->get_handle (i),
+   int n = pipe_data_available (s->fd, fh, fh->get_fc_handle (i),
 false);
if (n > 0)
  {
-- 
2.17.0



[PATCH 06/14] Cygwin: check for STATUS_PENDING in fhandler_base::raw_read

2019-04-14 Thread Ken Brown
If NtReadFile returns STATUS_PENDING, wait for the read to complete.
This can happen, for instance, in the case of a FIFO opened with
O_RDRW.
---
 winsup/cygwin/fhandler.cc | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index b0c9c50c3..a0c3dcce2 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -215,11 +215,23 @@ fhandler_base::raw_read (void *ptr, size_t& len)
   NTSTATUS status;
   IO_STATUS_BLOCK io;
   int try_noreserve = 1;
+  DWORD waitret = WAIT_OBJECT_0;
 
 retry:
   status = NtReadFile (get_handle (), NULL, NULL, NULL, &io, ptr, len,
   NULL, NULL);
-  if (NT_SUCCESS (status))
+  if (status == STATUS_PENDING)
+{
+  waitret = cygwait (get_handle (), cw_infinite,
+cw_cancel | cw_sig_eintr);
+  if (waitret == WAIT_OBJECT_0)
+   status = io.Status;
+}
+  if (waitret == WAIT_CANCELED)
+pthread::static_cancel_self ();
+  else if (waitret == WAIT_SIGNALED)
+set_errno (EINTR);
+  else if (NT_SUCCESS (status))
 len = io.Information;
   else
 {
-- 
2.17.0



[PATCH 02/14] Cygwin: FIFO: hit_eof: add a call to fifo_client_lock

2019-04-14 Thread Ken Brown
The second check of nconnected needs to be protected by a lock as well
as the first.
---
 winsup/cygwin/fhandler_fifo.cc | 21 +
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 901696444..70551ebac 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -705,15 +705,20 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
 bool
 fhandler_fifo::hit_eof ()
 {
-  fifo_client_lock ();
-  bool eof = (nconnected == 0);
-  fifo_client_unlock ();
-  if (eof)
-{
-  /* Give the listen_client thread time to catch up, then recheck. */
-  Sleep (1);
+  bool eof;
+  bool retry = true;
+
+retry:
+  fifo_client_lock ();
   eof = (nconnected == 0);
-}
+  fifo_client_unlock ();
+  if (eof && retry)
+   {
+ retry = false;
+ /* Give the listen_client thread time to catch up. */
+ Sleep (1);
+ goto retry;
+   }
   return eof;
 }
 
-- 
2.17.0



[PATCH 10/14] Cygwin: FIFO: use a retry loop when opening a writer

2019-04-14 Thread Ken Brown
There may be short periods when there's no pipe instance available.
Keep trying.
---
 winsup/cygwin/fhandler_fifo.cc | 52 --
 1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 479021e8e..d4d2b3883 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -30,6 +30,12 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
   || _s == STATUS_PIPE_BROKEN \
   || _s == STATUS_PIPE_EMPTY; })
 
+#define STATUS_PIPE_NO_INSTANCE_AVAILABLE(status)  \
+   ({ NTSTATUS _s = (status); \
+  _s == STATUS_INSTANCE_NOT_AVAILABLE \
+  || _s == STATUS_PIPE_NOT_AVAILABLE \
+  || _s == STATUS_PIPE_BUSY; })
+
 fhandler_fifo::fhandler_fifo ():
   fhandler_base (), read_ready (NULL), write_ready (NULL),
   listen_client_thr (NULL), lct_termination_evt (NULL), nhandlers (0),
@@ -543,28 +549,32 @@ fhandler_fifo::open (int flags, mode_t)
  listen_client thread is running.  Then signal write_ready.  */
   if (writer)
 {
-  if (!wait (read_ready))
-   {
- res = error_errno_set;
- goto out;
-   }
-  NTSTATUS status = open_pipe ();
-  if (!NT_SUCCESS (status))
-   {
- debug_printf ("create of writer failed");
- __seterrno_from_nt_status (status);
- res = error_errno_set;
- goto out;
-   }
-  else if (!arm (write_ready))
+  while (1)
{
- res = error_set_errno;
- goto out;
-   }
-  else
-   {
- set_pipe_non_blocking (get_handle (), true);
- res = success;
+ if (!wait (read_ready))
+   {
+ res = error_errno_set;
+ goto out;
+   }
+ NTSTATUS status = open_pipe ();
+ if (NT_SUCCESS (status))
+   {
+ set_pipe_non_blocking (get_handle (), true);
+ if (!arm (write_ready))
+   res = error_set_errno;
+ else
+   res = success;
+ goto out;
+   }
+ else if (STATUS_PIPE_NO_INSTANCE_AVAILABLE (status))
+   Sleep (1);
+ else
+   {
+ debug_printf ("create of writer failed");
+ __seterrno_from_nt_status (status);
+ res = error_errno_set;
+ goto out;
+   }
}
 }
 out:
-- 
2.17.0



[PATCH 01/14] Cygwin: FIFO: rename client[] to fc_handler[]

2019-04-14 Thread Ken Brown
The word "client" suggests something that holds a handle to the client
side of the pipe (in Windows terminology).  But our
fifo_client_handlers hold a handle the server side of the pipe, and
they *connect* to clients.
---
 winsup/cygwin/fhandler.h   | 20 +++
 winsup/cygwin/fhandler_fifo.cc | 96 +-
 winsup/cygwin/select.cc|  2 +-
 3 files changed, 59 insertions(+), 59 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index bc66377cd..2898db4df 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1269,8 +1269,8 @@ class fhandler_fifo: public fhandler_base
   HANDLE lct_termination_evt;
   UNICODE_STRING pipe_name;
   WCHAR pipe_name_buf[CYGWIN_FIFO_PIPE_NAME_LEN + 1];
-  fifo_client_handler client[MAX_CLIENTS];
-  int nclients, nconnected;
+  fifo_client_handler fc_handler[MAX_CLIENTS];
+  int nhandlers, nconnected;
   af_unix_spinlock_t _fifo_client_lock;
   bool _duplexer;
   bool __reg2 wait (HANDLE);
@@ -1278,15 +1278,15 @@ class fhandler_fifo: public fhandler_base
   HANDLE create_pipe_instance (bool);
   NTSTATUS open_pipe ();
   int disconnect_and_reconnect (int);
-  int add_client ();
+  int add_client_handler ();
   bool listen_client ();
 public:
   fhandler_fifo ();
   bool hit_eof ();
-  int get_nclients () const { return nclients; }
+  int get_nhandlers () const { return nhandlers; }
   HANDLE& get_handle () { return fhandler_base::get_handle (); }
-  HANDLE get_handle (int i) const { return client[i].fh->get_handle (); }
-  bool is_connected (int i) const { return client[i].state == fc_connected; }
+  HANDLE get_handle (int i) const { return fc_handler[i].fh->get_handle (); }
+  bool is_connected (int i) const { return fc_handler[i].state == 
fc_connected; }
   PUNICODE_STRING get_pipe_name ();
   DWORD listen_client_thread ();
   void fifo_client_lock () { _fifo_client_lock.lock (); }
@@ -1305,8 +1305,8 @@ public:
   void clear_readahead ()
   {
 fhandler_base::clear_readahead ();
-for (int i = 0; i < nclients; i++)
-  client[i].fh->clear_readahead ();
+for (int i = 0; i < nhandlers; i++)
+  fc_handler[i].fh->clear_readahead ();
   }
   select_record *select_read (select_stuff *);
   select_record *select_write (select_stuff *);
@@ -1326,8 +1326,8 @@ public:
 void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_fifo));
 fhandler_fifo *fhf = new (ptr) fhandler_fifo (ptr);
 copyto (fhf);
-for (int i = 0; i < nclients; i++)
-  fhf->client[i].fh = client[i].fh->clone ();
+for (int i = 0; i < nhandlers; i++)
+  fhf->fc_handler[i].fh = fc_handler[i].fh->clone ();
 return fhf;
   }
 };
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 68b9e7717..901696444 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -32,7 +32,7 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
 
 fhandler_fifo::fhandler_fifo ():
   fhandler_base (), read_ready (NULL), write_ready (NULL),
-  listen_client_thr (NULL), lct_termination_evt (NULL), nclients (0),
+  listen_client_thr (NULL), lct_termination_evt (NULL), nhandlers (0),
   nconnected (0), _duplexer (false)
 {
   pipe_name_buf[0] = L'\0';
@@ -146,7 +146,7 @@ fhandler_fifo::disconnect_and_reconnect (int i)
 {
   NTSTATUS status;
   IO_STATUS_BLOCK io;
-  HANDLE ph = client[i].fh->get_handle ();
+  HANDLE ph = fc_handler[i].fh->get_handle ();
 
   status = NtFsControlFile (ph, NULL, NULL, NULL, &io, FSCTL_PIPE_DISCONNECT,
NULL, 0, NULL, 0);
@@ -159,10 +159,10 @@ fhandler_fifo::disconnect_and_reconnect (int i)
   __seterrno_from_nt_status (status);
   return -1;
 }
-  set_pipe_non_blocking (client[i].fh->get_handle (), false);
-  if (client[i].connect () < 0)
+  set_pipe_non_blocking (fc_handler[i].fh->get_handle (), false);
+  if (fc_handler[i].connect () < 0)
 return -1;
-  if (client[i].state == fc_connected)
+  if (fc_handler[i].state == fc_connected)
 nconnected++;
   return 0;
 }
@@ -198,9 +198,9 @@ fhandler_fifo::npfs_handle (HANDLE &nph)
 }
 
 /* Called when a FIFO is first opened for reading and again each time
-   a new client is needed.  Each pipe instance is created in blocking
-   mode so that we can easily wait for a connection.  After it is
-   connected, it is put in nonblocking mode. */
+   a new client handler is needed.  Each pipe instance is created in
+   blocking mode so that we can easily wait for a connection.  After
+   it is connected, it is put in nonblocking mode. */
 HANDLE
 fhandler_fifo::create_pipe_instance (bool first)
 {
@@ -271,13 +271,13 @@ fhandler_fifo::open_pipe ()
 }
 
 int
-fhandler_fifo::add_client ()
+fhandler_fifo::add_client_handler ()
 {
   fifo_client_handler fc;
   fhandler_base *fh;
-  bool first = (nclients == 0);
+  bool first = (nhandlers == 0);
 
-  if (nclients == MAX_CLIENTS)
+  if (nhandlers == MAX_CLIENTS)
 {
   set_errno (EMFI

[PATCH 08/14] Cygwin: FIFO: fix fifo_client_handler::close

2019-04-14 Thread Ken Brown
Make sure that fhandler_base::close rather than fhandler_fifo::close
is called on the fhandler.  Also, delete the fhandler, since we
allocated it.
---
 winsup/cygwin/fhandler_fifo.cc | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 2da579b95..f9796f300 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -809,7 +809,10 @@ fifo_client_handler::close ()
   int res = 0;
 
   if (fh)
-res = fh->close ();
+{
+  res = fh->fhandler_base::close ();
+  delete fh;
+}
   if (connect_evt)
 CloseHandle (connect_evt);
   if (dummy_evt)
-- 
2.17.0



[PATCH 05/14] Cygwin: FIFO: fix the error checking in raw_read

2019-04-14 Thread Ken Brown
If the pipe is empty, we can get either ERROR_NO_DATA or
ERROR_PIPE_LISTENING.
---
 winsup/cygwin/fhandler_fifo.cc | 13 +
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 764420ffd..2da579b95 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -749,19 +749,16 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len)
fifo_client_unlock ();
return;
  }
-   /* In the duplex case with no data, we seem to get nread
-  == -1 with ERROR_PIPE_LISTENING on the first attempt to
-  read from the duplex pipe (fc_handler[0]), and nread == 0
-  on subsequent attempts. */
+   /* If the pipe is empty, we usually get nread == -1 with
+  ERROR_NO_DATA or ERROR_PIPE_LISTENING.  An exception is
+  that in the duplex case we may get nread == 0 when we
+  attempt to read from the duplex pipe (fc_handler[0]). */
else if (nread < 0)
  switch (GetLastError ())
{
case ERROR_NO_DATA:
- break;
case ERROR_PIPE_LISTENING:
- if (_duplexer && i == 0)
-   break;
- /* Fall through. */
+ break;
default:
  fifo_client_unlock ();
  goto errout;
-- 
2.17.0



[PATCH 09/14] Cygwin: FIFO: fix the use of the read_ready event

2019-04-14 Thread Ken Brown
Make read_ready a manual reset event.  It should always be set shortly
after startup of the listen_client thread and remain set until the
thread terminates.  (We don't want writers to connect without being
recorded in the client handler list.)

Remove the unnecessary code that checks for read_ready when a reader
is opening.
---
 winsup/cygwin/fhandler_fifo.cc | 51 +++---
 1 file changed, 16 insertions(+), 35 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index f9796f300..479021e8e 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -344,6 +344,8 @@ fhandler_fifo::listen_client ()
 DWORD
 fhandler_fifo::listen_client_thread ()
 {
+  DWORD ret = -1;
+
   while (1)
 {
   bool found;
@@ -360,7 +362,7 @@ fhandler_fifo::listen_client_thread ()
if (disconnect_and_reconnect (i) < 0)
  {
fifo_client_unlock ();
-   goto errout;
+   goto out;
  }
else
  /* Recheck fc_handler[i].state. */
@@ -383,23 +385,27 @@ fhandler_fifo::listen_client_thread ()
res = add_client_handler ();
   fifo_client_unlock ();
   if (res < 0)
-   goto errout;
+   goto out;
   else if (!found)
continue;
 
+  /* Allow a writer to open. */
   if (!arm (read_ready))
{
  __seterrno ();
- goto errout;
+ goto out;
}
 
   /* Wait for a client to connect. */
   wait_ret = WaitForMultipleObjects (nhandlers + 1, w, false, INFINITE);
   i = wait_ret - WAIT_OBJECT_0;
   if (i < 0 || i > nhandlers)
-   goto errout;
-  else if (i == nhandlers) /* Reader is closing. */
-   return 0;
+   goto out;
+  else if (i == nhandlers) /* Thread termination requested. */
+   {
+ ret = 0;
+ goto out;
+   }
   else
{
  fifo_client_lock ();
@@ -410,9 +416,9 @@ fhandler_fifo::listen_client_thread ()
  yield ();
}
 }
-errout:
+out:
   ResetEvent (read_ready);
-  return -1;
+  return ret;
 }
 
 int
@@ -457,7 +463,7 @@ fhandler_fifo::open (int flags, mode_t)
 
   char npbuf[MAX_PATH];
   __small_sprintf (npbuf, "r-event.%08x.%016X", get_dev (), get_ino ());
-  if (!(read_ready = CreateEvent (sa_buf, duplexer, false, npbuf)))
+  if (!(read_ready = CreateEvent (sa_buf, true, false, npbuf)))
 {
   debug_printf ("CreateEvent for %s failed, %E", npbuf);
   res = error_set_errno;
@@ -523,32 +529,7 @@ fhandler_fifo::open (int flags, mode_t)
  res = error_errno_set;
  goto out;
}
-  /* Wait for the listen_client thread to signal read_ready.  This
-should be quick.  */
-  HANDLE w[2] = { listen_client_thr, read_ready };
-  switch (WaitForMultipleObjects (2, w, FALSE, INFINITE))
-   {
-   case WAIT_OBJECT_0:
- debug_printf ("listen_client_thread exited unexpectedly");
- DWORD err;
- GetExitCodeThread (listen_client_thr, &err);
- __seterrno_from_win_error (err);
- res = error_errno_set;
- goto out;
- break;
-   case WAIT_OBJECT_0 + 1:
- if (!arm (read_ready))
-   {
- res = error_set_errno;
- goto out;
-   }
- break;
-   default:
- res = error_set_errno;
- goto out;
- break;
-   }
-  if (!duplexer && !wait (write_ready))
+  else if (!duplexer && !wait (write_ready))
{
  res = error_errno_set;
  goto out;
-- 
2.17.0



[PATCH 12/14] Cygwin: FIFO: start the listen_client thread when duping a reader

2019-04-14 Thread Ken Brown
Otherwise it doesn't get started until the dup'd fd tries to read,
which delays client connections.
---
 winsup/cygwin/fhandler_fifo.cc | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index a3ecbeb4a..fe4c67bdf 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -853,19 +853,20 @@ fhandler_fifo::close ()
 int
 fhandler_fifo::dup (fhandler_base *child, int flags)
 {
+  int ret = -1;
+  fhandler_fifo *fhf = NULL;
+
   if (fhandler_base::dup (child, flags))
-{
-  __seterrno ();
-  return -1;
-}
-  fhandler_fifo *fhf = (fhandler_fifo *) child;
+goto out;
+
+  fhf = (fhandler_fifo *) child;
   if (!DuplicateHandle (GetCurrentProcess (), read_ready,
GetCurrentProcess (), &fhf->read_ready,
0, true, DUPLICATE_SAME_ACCESS))
 {
   fhf->close ();
   __seterrno ();
-  return -1;
+  goto out;
 }
   if (!DuplicateHandle (GetCurrentProcess (), write_ready,
GetCurrentProcess (), &fhf->write_ready,
@@ -874,7 +875,7 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
   CloseHandle (fhf->read_ready);
   fhf->close ();
   __seterrno ();
-  return -1;
+  goto out;
 }
   for (int i = 0; i < nhandlers; i++)
 {
@@ -895,13 +896,16 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
  CloseHandle (fhf->write_ready);
  fhf->close ();
  __seterrno ();
- return -1;
+ goto out;
}
 }
   fhf->listen_client_thr = NULL;
   fhf->lct_termination_evt = NULL;
   fhf->fifo_client_unlock ();
-  return 0;
+  if (!reader || fhf->listen_client ())
+ret = 0;
+out:
+  return ret;
 }
 
 void
-- 
2.17.0



[PATCH 14/14] Cygwin: FIFO: fix and simplify listen_client_thread

2019-04-14 Thread Ken Brown
Remove fifo_client_handler::connect and move its code into
listen_client_thread.  That way we can check the return status when a
client handler's connect_evt is signaled.  Previously we incorrectly
assumed there was a successful connection.

Also simplify listen_client_thread in the following ways:

- Replace fhandler_fifo::disconnect_and_reconnect by a new
  delete_client_handler method.  Now we just delete invalid client
  handlers rather than trying to re-use them.

- Try to maintain a client handler list that consists of connected
  client handlers and exactly one that is listening for a connection.
  This allows us to call WaitForMultipleObjects with only two wait
  objects.

- Remove 'dummy_evt' from the fifo_client_handler struct; it is no
  longer needed.

- On exit from listen_client_thread, delete the "extra" (listening)
  client handler.  Otherwise there could be a connection that doesn't
  get recorded in the client handler list.  This could happen when a
  file descriptor is being duplicated.
---
 winsup/cygwin/fhandler.h   |  11 +-
 winsup/cygwin/fhandler_fifo.cc | 251 ++---
 2 files changed, 109 insertions(+), 153 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index fd205a6db..8fb176b24 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1250,13 +1250,10 @@ struct fifo_client_handler
   fhandler_base *fh;
   fifo_client_connect_state state;
   HANDLE connect_evt;
-  HANDLE dummy_evt;/* Never signaled. */
-  fifo_client_handler () : fh (NULL), state (fc_unknown), connect_evt (NULL),
-  dummy_evt (NULL) {}
+  fifo_client_handler () : fh (NULL), state (fc_unknown), connect_evt (NULL) {}
   fifo_client_handler (fhandler_base *_fh, fifo_client_connect_state _state,
-  HANDLE _connect_evt, HANDLE _dummy_evt)
-: fh (_fh), state (_state), connect_evt (_connect_evt),
-  dummy_evt (_dummy_evt) {}
+  HANDLE _connect_evt)
+: fh (_fh), state (_state), connect_evt (_connect_evt) {}
   int connect ();
   int close ();
 };
@@ -1278,8 +1275,8 @@ class fhandler_fifo: public fhandler_base
   NTSTATUS npfs_handle (HANDLE &);
   HANDLE create_pipe_instance (bool);
   NTSTATUS open_pipe ();
-  int disconnect_and_reconnect (int);
   int add_client_handler ();
+  void delete_client_handler (int);
   bool listen_client ();
   int stop_listen_client ();
 public:
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index ce078d74d..abbb29a61 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -121,62 +121,6 @@ set_pipe_non_blocking (HANDLE ph, bool nonblocking)
 debug_printf ("NtSetInformationFile(FilePipeInformation): %y", status);
 }
 
-/* The pipe instance is always in blocking mode when this is called. */
-int
-fifo_client_handler::connect ()
-{
-  NTSTATUS status;
-  IO_STATUS_BLOCK io;
-
-  if (connect_evt)
-ResetEvent (connect_evt);
-  else if (!(connect_evt = create_event ()))
-return -1;
-  status = NtFsControlFile (fh->get_handle (), connect_evt, NULL, NULL, &io,
-   FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
-  switch (status)
-{
-case STATUS_PENDING:
-case STATUS_PIPE_LISTENING:
-  state = fc_connecting;
-  break;
-case STATUS_PIPE_CONNECTED:
-  state = fc_connected;
-  set_pipe_non_blocking (fh->get_handle (), true);
-  break;
-default:
-  __seterrno_from_nt_status (status);
-  return -1;
-}
-  return 0;
-}
-
-int
-fhandler_fifo::disconnect_and_reconnect (int i)
-{
-  NTSTATUS status;
-  IO_STATUS_BLOCK io;
-  HANDLE ph = fc_handler[i].fh->get_handle ();
-
-  status = NtFsControlFile (ph, NULL, NULL, NULL, &io, FSCTL_PIPE_DISCONNECT,
-   NULL, 0, NULL, 0);
-  /* Short-lived.  Don't use cygwait.  We don't want to be interrupted. */
-  if (status == STATUS_PENDING
-  && NtWaitForSingleObject (ph, FALSE, NULL) == WAIT_OBJECT_0)
-status = io.Status;
-  if (!NT_SUCCESS (status))
-{
-  __seterrno_from_nt_status (status);
-  return -1;
-}
-  set_pipe_non_blocking (fc_handler[i].fh->get_handle (), false);
-  if (fc_handler[i].connect () < 0)
-return -1;
-  if (fc_handler[i].state == fc_connected)
-nconnected++;
-  return 0;
-}
-
 NTSTATUS
 fhandler_fifo::npfs_handle (HANDLE &nph)
 {
@@ -283,41 +227,49 @@ fhandler_fifo::open_pipe ()
 int
 fhandler_fifo::add_client_handler ()
 {
+  int ret = -1;
   fifo_client_handler fc;
   fhandler_base *fh;
+  HANDLE ph = NULL;
   bool first = (nhandlers == 0);
 
   if (nhandlers == MAX_CLIENTS)
 {
   set_errno (EMFILE);
-  return -1;
+  goto out;
 }
-  if (!(fc.dummy_evt = create_event ()))
-return -1;
+  if (!(fc.connect_evt = create_event ()))
+goto out;
   if (!(fh = build_fh_dev (dev (
 {
   set_errno (EMFILE);
-  return -1;
+  goto out;
 }
-  fc.fh = fh;
-  HAN

[PATCH v2 13/14] Cygwin: FIFO: improve raw_write

2019-04-15 Thread Ken Brown
Don't set the write end of the pipe to non-blocking mode if the FIFO
is opened in blocking mode.

In fhandler_fifo::raw_write in blocking mode, wait for the write to
complete rather than returning -1 with EAGAIN.

If the amount to write is large, write in smaller chunks (of size
determined by a new data member max_atomic_write), as in
fhandler_base_overlapped.

For convenience, add two new NTSTATUS codes, STATUS_THREAD_SIGNALED
and STATUS_THREAD_CANCELED, to ntdll.h.
---
 winsup/cygwin/fhandler.h   |  1 +
 winsup/cygwin/fhandler_fifo.cc | 95 +++---
 winsup/cygwin/ntdll.h  |  4 +-
 3 files changed, 80 insertions(+), 20 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index aea02c2b3..fd205a6db 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1273,6 +1273,7 @@ class fhandler_fifo: public fhandler_base
   int nhandlers, nconnected;
   af_unix_spinlock_t _fifo_client_lock;
   bool reader, writer, duplexer;
+  size_t max_atomic_write;
   bool __reg2 wait (HANDLE);
   NTSTATUS npfs_handle (HANDLE &);
   HANDLE create_pipe_instance (bool);
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index fe4c67bdf..d2f8b99bc 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -39,7 +39,8 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
 fhandler_fifo::fhandler_fifo ():
   fhandler_base (), read_ready (NULL), write_ready (NULL),
   listen_client_thr (NULL), lct_termination_evt (NULL), nhandlers (0),
-  nconnected (0), reader (false), writer (false), duplexer (false)
+  nconnected (0), reader (false), writer (false), duplexer (false),
+  max_atomic_write (DEFAULT_PIPEBUFSIZE)
 {
   pipe_name_buf[0] = L'\0';
   need_fork_fixup (true);
@@ -559,7 +560,7 @@ fhandler_fifo::open (int flags, mode_t)
  NTSTATUS status = open_pipe ();
  if (NT_SUCCESS (status))
{
- set_pipe_non_blocking (get_handle (), true);
+ set_pipe_non_blocking (get_handle (), flags & O_NONBLOCK);
  if (!arm (write_ready))
res = error_set_errno;
  else
@@ -661,28 +662,84 @@ ssize_t __reg3
 fhandler_fifo::raw_write (const void *ptr, size_t len)
 {
   ssize_t ret = -1;
-  NTSTATUS status;
+  size_t nbytes = 0, chunk;
+  NTSTATUS status = STATUS_SUCCESS;
   IO_STATUS_BLOCK io;
+  HANDLE evt = NULL;
 
-  status = NtWriteFile (get_handle (), NULL, NULL, NULL, &io,
-   (PVOID) ptr, len, NULL, NULL);
-  if (NT_SUCCESS (status))
+  if (len <= max_atomic_write)
+chunk = len;
+  else if (is_nonblocking ())
+chunk = len = max_atomic_write;
+  else
+chunk = max_atomic_write;
+
+  /* Create a wait event if the FIFO is in blocking mode. */
+  if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
+return -1;
+
+  /* Write in chunks, accumulating a total.  If there's an error, just
+ return the accumulated total unless the first write fails, in
+ which case return -1. */
+  while (nbytes < len)
 {
-  /* NtWriteFile returns success with # of bytes written == 0 in
-case writing on a non-blocking pipe fails if the pipe buffer
-is full. */
-  if (io.Information == 0)
-   set_errno (EAGAIN);
+  ULONG_PTR nbytes_now = 0;
+  size_t left = len - nbytes;
+  size_t len1;
+  if (left > chunk)
+   len1 = chunk;
   else
-   ret = io.Information;
-}
-  else if (STATUS_PIPE_IS_CLOSED (status))
-{
-  set_errno (EPIPE);
-  raise (SIGPIPE);
+   len1 = left;
+  nbytes_now = 0;
+  status = NtWriteFile (get_handle (), evt, NULL, NULL, &io,
+   (PVOID) ptr, len1, NULL, NULL);
+  if (evt && status == STATUS_PENDING)
+   {
+ DWORD waitret = cygwait (evt, cw_infinite, cw_cancel | cw_sig_eintr);
+ switch (waitret)
+   {
+   case WAIT_OBJECT_0:
+ status = io.Status;
+ break;
+   case WAIT_SIGNALED:
+ status = STATUS_THREAD_SIGNALED;
+ break;
+   case WAIT_CANCELED:
+ status = STATUS_THREAD_CANCELED;
+ break;
+   default:
+ break;
+   }
+   }
+  if (NT_SUCCESS (status))
+   {
+ nbytes_now = io.Information;
+ /* NtWriteFile returns success with # of bytes written == 0
+if writing on a non-blocking pipe fails because the pipe
+buffer doesn't have sufficient space. */
+ if (nbytes_now == 0)
+   set_errno (EAGAIN);
+ ptr = ((char *) ptr) + chunk;
+ nbytes += nbytes_now;
+   }
+  else if (STATUS_PIPE_IS_CLOSED (status))
+   {
+ set_errno (EPIPE);
+ raise (SIGPIPE);
+   }
+  else
+   __seterrno_from_nt_status (status);
+  if (nbytes_now == 0)
+   len = 0;/* Terminate loop. */
+  

Re: [PATCH 00/14] FIFO bug fixes and code simplifications

2019-04-17 Thread Ken Brown
On 4/17/2019 1:23 PM, Achim Gratz wrote:
> Corinna Vinschen writes:
>> Pushed with v2 of patch 13.  Developer snaps should be up shortly.
> 
> I gave the snapshot some testing today.
> 
> The good news is that the named FIFO branch of our code works correctly
> again and is faster than going through pseudo-file STDIO pipes.
> 
> The bad news is that there is still some problem that seems to hit while
> forking.  I've got an empty stackdump file from sh (which gets used when
> exec'ing due to the way perl implements that) a few times and also one
> error message about a terminated thread due to "Windows WFSO error 6"
> (hilariously the output file was produced correctly in that case).  But
> most of the time the processes in my data pipeline would all have execed
> correctly, but then none of them ever gets runnable again.  So this
> seems to be something of a race around the exec.  If I kill the stalled
> processes and start the same commands again, then everything works as it
> should most of the time.

Thanks for testing.  I have STCs for fork and exec that I used when first 
writing the code, and I forgot to retest those after the recent changes.  I 
just 
tried, and the fork test succeeds but the exec test fails.  I'll try to debug 
that.

Ken


[PATCH] Cygwin: FIFO: avoid hang after exec

2019-04-18 Thread Ken Brown
Define fhandler:fifo::fixup_after_exec, which sets listen_client_thr
and lct_termination_evt to NULL.  This forces the listen_client thread
to restart on the first attempt to read after an exec.  Previously the
exec'd process could hang in fhandler_fifo::raw_read.
---
 winsup/cygwin/fhandler.h   | 1 +
 winsup/cygwin/fhandler_fifo.cc | 9 +
 2 files changed, 10 insertions(+)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 8fb176b24..da007ee45 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1301,6 +1301,7 @@ public:
   ssize_t __reg3 raw_write (const void *ptr, size_t ulen);
   bool arm (HANDLE h);
   void fixup_after_fork (HANDLE);
+  void fixup_after_exec ();
   int __reg2 fstatvfs (struct statvfs *buf);
   void clear_readahead ()
   {
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 1d02adbaa..bc9c23998 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -942,6 +942,15 @@ fhandler_fifo::fixup_after_fork (HANDLE parent)
   fifo_client_unlock ();
 }
 
+void
+fhandler_fifo::fixup_after_exec ()
+{
+  fhandler_base::fixup_after_exec ();
+  listen_client_thr = NULL;
+  lct_termination_evt = NULL;
+  fifo_client_unlock ();
+}
+
 void
 fhandler_fifo::set_close_on_exec (bool val)
 {
-- 
2.17.0



Re: [PATCH 00/14] FIFO bug fixes and code simplifications

2019-04-18 Thread Ken Brown
On 4/17/2019 2:58 PM, Achim Gratz wrote:
> Ken Brown writes:
>> Thanks for testing.  I have STCs for fork and exec that I used when first
>> writing the code, and I forgot to retest those after the recent changes.  I 
>> just
>> tried, and the fork test succeeds but the exec test fails.  I'll try to 
>> debug that.
> 
> Take your time and thanks for working in that area.

I've just sent an attempted fix.  There may still be more changes needed; I 
just 
made a minimal change to make my STC succeed.

Ken


Re: Cygwin patches (was Re: [PATCH 00/14] FIFO bug fixes and code simplifications)

2019-04-18 Thread Ken Brown
On 4/18/2019 3:04 PM, Corinna Vinschen wrote:
> Ken, you have an account on sware and check-in rights to the cygwin repo
> anyway, so you don't really need me to push patches.
> 
> If you feel up to the task, you can also go ahead and review and
> ultimately push patches from others.  This also applies to Takashi's
> ConPTY patch as soon as he wants to go mainline,

I can do that.

> as well as Mark's
> sched_[gs]etaffinity patches, after review.

I'm not sure I'm qualified to review these, but maybe he won't wait until May :)

Ken


[PATCH 3/5] Cygwin: FIFO: avoid WFMO error in listen_client_thread

2019-04-20 Thread Ken Brown
Don't set lct_termination_evt to NULL too early in
fhandler_fifo::stop_listen_client.  Doing so leads to an "Invalid
Handle" error in WFMO.
---
 winsup/cygwin/fhandler_fifo.cc | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 0a6dc0591..0e4bf3aee 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -844,22 +844,24 @@ int
 fhandler_fifo::stop_listen_client ()
 {
   int ret = 0;
-  HANDLE evt = InterlockedExchangePointer (&lct_termination_evt, NULL);
-  HANDLE thr = InterlockedExchangePointer (&listen_client_thr, NULL);
+  HANDLE thr, evt;
+
+  thr = InterlockedExchangePointer (&listen_client_thr, NULL);
   if (thr)
 {
-  if (evt)
-   SetEvent (evt);
+  if (lct_termination_evt)
+   SetEvent (lct_termination_evt);
   WaitForSingleObject (thr, INFINITE);
   DWORD err;
   GetExitCodeThread (thr, &err);
   if (err)
{
  ret = -1;
- debug_printf ("listen_client_thread exited with error, %E");
+ debug_printf ("listen_client_thread exited with error");
}
   CloseHandle (thr);
 }
+  evt = InterlockedExchangePointer (&lct_termination_evt, NULL);
   if (evt)
 CloseHandle (evt);
   return ret;
-- 
2.17.0



[PATCH 4/5] Cygwin: FIFO: close connect_evt handles as soon as possible

2019-04-20 Thread Ken Brown
Keeping them open too long can cause an attempt to close them twice
after a fork or exec.
---
 winsup/cygwin/fhandler_fifo.cc | 17 ++---
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 0e4bf3aee..3ee307bcc 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -363,6 +363,7 @@ fhandler_fifo::listen_client_thread ()
  break;
}
}
+ HANDLE evt = NULL;
  switch (status)
{
case STATUS_SUCCESS:
@@ -371,6 +372,9 @@ fhandler_fifo::listen_client_thread ()
  fc.state = fc_connected;
  nconnected++;
  set_pipe_non_blocking (fc.fh->get_handle (), true);
+ evt = InterlockedExchangePointer (&fc.connect_evt, NULL);
+ if (evt)
+   CloseHandle (evt);
  fifo_client_unlock ();
  break;
case STATUS_PIPE_LISTENING:
@@ -400,6 +404,8 @@ fhandler_fifo::listen_client_thread ()
}
 }
 out:
+  if (ret < 0)
+debug_printf ("exiting lct with error, %E");
   ResetEvent (read_ready);
   return ret;
 }
@@ -829,14 +835,15 @@ int
 fifo_client_handler::close ()
 {
   int res = 0;
+  HANDLE evt = InterlockedExchangePointer (&connect_evt, NULL);
 
+  if (evt)
+CloseHandle (evt);
   if (fh)
 {
   res = fh->fhandler_base::close ();
   delete fh;
 }
-  if (connect_evt)
-CloseHandle (connect_evt);
   return res;
 }
 
@@ -913,11 +920,7 @@ fhandler_fifo::dup (fhandler_base *child, int flags)
   if (!DuplicateHandle (GetCurrentProcess (), fc_handler[i].fh->get_handle 
(),
GetCurrentProcess (),
&fhf->fc_handler[i].fh->get_handle (),
-   0, true, DUPLICATE_SAME_ACCESS)
- || !DuplicateHandle (GetCurrentProcess (), fc_handler[i].connect_evt,
-  GetCurrentProcess (),
-  &fhf->fc_handler[i].connect_evt,
-  0, true, DUPLICATE_SAME_ACCESS))
+   0, true, DUPLICATE_SAME_ACCESS))
{
  CloseHandle (fhf->read_ready);
  CloseHandle (fhf->write_ready);
-- 
2.17.0



  1   2   3   4   5   >