This is the mail archive of the cygwin-patches mailing list for the Cygwin project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Add wrappers for ExitProcess, TerminateProcess

Normally, posix programs should call abort(), exit(), _exit(), kill() --
or various pthread functions -- to terminate operation (either their
own, or that of some other processes/thread).  However, there are two
cases where the win32 ExitProcess and TerminateProcess functions might
justifiably be called:
  1) inside cygwin's own process startup/shutdown implementation
  2) "Native" programs that use the w32api throughout, but are compiled
using the cygwin compiler (e.g. without -mno-cygwin). [*]

However, the ExitProcess and TerminateProcess functions, when called
directly, do not allow for the 'exit status' maintained by cygwin to be
set. This can be a problem when such cygwin applications are exec'ed by
other cygwin apps: cygwin's code for exec'ing children doesn't ever
check the value of GetExitCodeProcess as set by these win32 functions,
if the child application is also a cygwin app.

The attached patch address this problem, by providing two wrappers:
  cygwin_terminate_process <--> TerminateProcess
  cygwin_exit_process      <--> ExitProcess
which simply set the cygwin exit code using the specified status value,
and then delegate to the underlying win32 call. This way, the parent
process -- if it is a cygwin process -- can access the exit code as

Note that TerminateProcess/ExitProcess -- and the new wrappers -- bypass
most of the cygwin shutdown code, so it is not recommended that ANY of
these functions be used in normal cygwin applications; they should be
used only when necessary -- e.g. case #1 above.

[*] In case #2, even with this patch, the client code must be modified
to call the wrappers. We can, in a follow-up patch, add objects to
libcygwin.a that explicitly force using the wrappers when client code
calls ExitProcess/TerminateProcess, but I'm not sure that's a good idea,
so I deferred that decision. Furthermore, if you're going to modify the
source code of the client, you might as well modify it to use the
recommended posix functions, in actuality, it's just case
#1 that really needs this support.

So, how should cygwin's process startup/shutdown code use these new
functions? Well, this can serve as the beginnings of a generic mechanism
for deferring error messages on process startup, using custom NTSTATUS
values (which have bit 29 set: eg. 0x[ea62]0000000).  At present, cygwin
maps any NTSTATUS values greater than 0xc00000000 to a posix exit value
of 127, because when bits 30 and 31 are set, this means
"STATUS_SEVERITY_ERROR", and cygwin assumes that these NTSTATUS values
will only occur during process startup -- thus, a posix 127 is
appropriate for "errors that occur during process startup". We could
revisit this assumption later.

One example of intended use is the v2 runtime pseudo-reloc stuff, posted
simultaneously on the cygwin-devel list.

But, here's a short example:
#include <stdio.h>
#include <windows.h>
#include <ntdef.h>
#include <sys/cygwin.h>

#define STATUS_ILLEGAL_DLL_RELOCATION        ((NTSTATUS) 0xc0000269)
#define STATUS_DLL_NOT_FOUND                 ((NTSTATUS) 0xc0000135)

/* custom NTSTATUS value */

int main(int argc, char* argv[])
//cygwin_terminate_process (GetCurrentProcess(),
  exit (1);

$ gcc -o foo foo.c
$ ./foo
$ echo $?

2009-10-04  Charles Wilson  <...>

	Add cygwin wrappers for ExitProcess and TerminateProcess.
	* include/sys/cygwin.h: Declare new functions
	cygwin_exit_process and cygwin_terminate_process.
	* cygwin.din: Add new functions cygwin_exit_process and
	* (cygwin_exit_process): New function.
	(cygwin_terminate_process): New function.
	* include/cygwin/version.h: Bump version.
	* pinfo.h (pinfo::set_exit_code): New method.
	* (pinfo::set_exit_code): New, refactored from...
	(pinfo::maybe_set_exit_code_from_windows): here. Call it.


Index: cygwin.din
RCS file: /cvs/src/src/winsup/cygwin/cygwin.din,v
retrieving revision 1.216
diff -u -p -r1.216 cygwin.din
--- cygwin.din	26 Sep 2009 21:01:10 -0000	1.216
+++ cygwin.din	5 Oct 2009 16:58:48 -0000
@@ -250,6 +250,7 @@ cygwin_conv_to_win32_path SIGFE
 cygwin_create_path SIGFE
 cygwin_detach_dll SIGFE_MAYBE
 cygwin_dll_init NOSIGFE
+cygwin_exit_process NOSIGFE
 cygwin_internal NOSIGFE
 cygwin_logon_user SIGFE
 cygwin_posix_path_list_p NOSIGFE
@@ -258,6 +259,7 @@ cygwin_posix_to_win32_path_list_buf_size
 cygwin_set_impersonation_token SIGFE
 cygwin_split_path NOSIGFE
 cygwin_stackdump SIGFE
+cygwin_terminate_process NOSIGFE
 cygwin_umount SIGFE
 cygwin_win32_to_posix_path_list SIGFE
 cygwin_win32_to_posix_path_list_buf_size SIGFE
RCS file: /cvs/src/src/winsup/cygwin/,v
retrieving revision 1.365
diff -u -p -r1.365
---	2 Oct 2009 14:58:10 -0000	1.365
+++	5 Oct 2009 17:40:17 -0000
@@ -41,6 +41,8 @@ details. */
 extern "C" void cygwin_exit (int) __attribute__ ((noreturn));
+extern "C" BOOL cygwin_terminate_process (HANDLE, UINT);
+extern "C" void cygwin_exit_process (UINT) __attribute__ ((noreturn));
 extern "C" void __sinit (_reent *);
 static int NO_COPY envc;
@@ -1136,6 +1138,67 @@ _exit (int n)
   do_exit (((DWORD) n & 0xff) << 8);
+ <title>cygwin_terminate_process</title>
+  <funcsynopsis><funcprototype>
+    <funcdef>extern "C" BOOL
+      <function>cygwin_terminate_process</function>
+      </funcdef>
+      <paramdef>HANDLE <parameter>process</parameter></paramdef>
+      <paramdef>UINT <parameter>status</parameter></paramdef>
+  </funcprototype></funcsynopsis>
+  <para>Cygwin-specific wrapper for win32 TerminateProcess. It
+ensures that if used to terminate the current process, then the
+correct exit code will be made available to this process's parent
+(if that parent is also a cygwin process). Otherwise, it simply
+delegates to the win32 TerminateProcess.</para>
+  <para>This function should be used in cygwin programs instead
+of TerminateProcess. Ordinarily, however, the ANSI abort() or the
+POSIX _exit() function should be preferred over either
+TerminateProcess or cygwin_terminate_process when used to terminate
+the current process. Similarly, the POSIX kill() function should
+be used to terminate cygwin processes other than the current one.
+extern "C" BOOL
+cygwin_terminate_process (HANDLE process, UINT status)
+  if (process == GetCurrentProcess())
+    myself.set_exit_code ((DWORD)status);
+  return TerminateProcess (process, status);
+ <title>cygwin_exit_process</title>
+  <funcsynopsis><funcprototype>
+    <funcdef>extern "C" void
+      <function>cygwin_exit_process</function>
+      </funcdef>
+      <paramdef>UINT <parameter>status</parameter></paramdef>
+  </funcprototype></funcsynopsis>
+  <para>Cygwin-specific wrapper for win32 ExitProcess, which
+ensures that parent cygwin process receives the specified status
+as an exit code, before calling ExitProcess. This function should
+be used in cygwin programs instead of ExitProcess. Ordinarily,
+however, the ANSI exit() function should be preferred over either
+ExitProcess or cygwin_exit_process.</para>
+extern "C" void
+cygwin_exit_process (UINT status)
+  myself.set_exit_code ((DWORD)status);
+  ExitProcess (status);
 extern "C" void
 __api_fatal (const char *fmt, ...)
RCS file: /cvs/src/src/winsup/cygwin/,v
retrieving revision 1.253
diff -u -p -r1.253
---	12 Jul 2009 21:15:47 -0000	1.253
+++	5 Oct 2009 16:58:49 -0000
@@ -136,11 +136,19 @@ status_exit (DWORD x)
 # define self (*this)
+pinfo::set_exit_code (DWORD x)
+  extern int sigExeced;
+  if (x >= 0xc0000000UL)
+    x = status_exit (x);
+  self->exitcode = EXITCODE_SET | (sigExeced ?: (x & 0xff) << 8);
 pinfo::maybe_set_exit_code_from_windows ()
   DWORD x = 0xdeadbeef;
   DWORD oexitcode = self->exitcode;
-  extern int sigExeced;
   if (hProcess && !(self->exitcode & EXITCODE_SET))
@@ -148,9 +160,7 @@ pinfo::maybe_set_exit_code_from_windows 
 						   process hasn't quite exited
 						   after closing pipe */
       GetExitCodeProcess (hProcess, &x);
-      if (x >= 0xc0000000UL)
-	x = status_exit (x);
-      self->exitcode = EXITCODE_SET | (sigExeced ?: (x & 0xff) << 8);
+      set_exit_code (x);
   sigproc_printf ("pid %d, exit value - old %p, windows %p, cygwin %p",
 		  self->pid, oexitcode, x, self->exitcode);
Index: pinfo.h
RCS file: /cvs/src/src/winsup/cygwin/pinfo.h,v
retrieving revision 1.108
diff -u -p -r1.108 pinfo.h
--- pinfo.h	20 Dec 2008 17:32:31 -0000	1.108
+++ pinfo.h	5 Oct 2009 16:58:49 -0000
@@ -155,6 +155,7 @@ public:
   void exit (DWORD n) __attribute__ ((noreturn, regparm(2)));
   void maybe_set_exit_code_from_windows () __attribute__ ((regparm(1)));
+  void set_exit_code (DWORD n) __attribute__ ((regparm(2)));
   _pinfo *operator -> () const {return procinfo;}
   int operator == (pinfo *x) const {return x->procinfo == procinfo;}
   int operator == (pinfo &x) const {return x.procinfo == procinfo;}
Index: include/cygwin/version.h
RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/version.h,v
retrieving revision 1.299
diff -u -p -r1.299 version.h
--- include/cygwin/version.h	26 Sep 2009 21:01:10 -0000	1.299
+++ include/cygwin/version.h	5 Oct 2009 16:58:49 -0000
@@ -368,12 +368,13 @@ details. */
       212: Add and export libstdc++ malloc wrappers.
       213: Export canonicalize_file_name, eaccess, euidaccess.
       214: Export execvpe, fexecve.
+      215: Export cygwin_terminate_process, cygwin_exit_process.
      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
      /* There is also a compatibity version number associated with the
 	shared memory regions.  It is incremented when incompatible
Index: include/sys/cygwin.h
RCS file: /cvs/src/src/winsup/cygwin/include/sys/cygwin.h,v
retrieving revision 1.80
diff -u -p -r1.80 cygwin.h
--- include/sys/cygwin.h	7 Jul 2009 20:12:44 -0000	1.80
+++ include/sys/cygwin.h	5 Oct 2009 16:58:49 -0000
@@ -94,6 +94,8 @@ extern void *cygwin_create_path (cygwin_
 extern pid_t cygwin_winpid_to_pid (int);
 extern int cygwin_posix_path_list_p (const char *);
 extern void cygwin_split_path (const char *, char *, char *);
+extern void cygwin_exit_process (unsigned int status) __attribute__((noreturn));
+extern BOOL cygwin_terminate_process (HANDLE process, unsigned int status);
 struct __cygwin_perfile

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]