This is the mail archive of the cygwin-cvs@cygwin.com 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]

[newlib-cygwin] Implement getcontext, setcontext, makecontext, swapcontext


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

commit 1020bb292aa0c19c487010aa1506c3d745ded6d5
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Fri Jul 17 14:31:12 2015 +0200

    Implement getcontext, setcontext, makecontext, swapcontext
    
            * common.din (getcontext): Export.
            (makecontext): Export.
            (setcontext): Export.
            (swapcontext): Export.
            * exceptions.cc (__unwind_single_frame): New static functions, 64 bit
            only.
            (setcontext): New function.
            (getcontext): New function.
            (swapcontext): New function.
            (__cont_link_context): New function.
            (makecontext): New function.
            * include/cygwin/version.h (CYGWIN_VERSION_DLL_MAJOR): Bump to 2002.
            (CYGWIN_VERSION_API_MINOR): Bump.
            * include/ucontext.h (getcontext): Add prototype.
            (setcontext): Ditto.
            (swapcontext): Ditto.
            (makecontext): Ditto.
            * ntdll.h (NtContinue): Ditto.
    
            * new-features.xml (ov-new2.2): Add new section.  Document getcontext,
            setcontext, makecontext, swapcontext.
            * posix.xml (std-deprec): Add getcontext, setcontext, makecontext,
            swapcontext.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/ChangeLog                |  21 ++++
 winsup/cygwin/common.din               |   4 +
 winsup/cygwin/exceptions.cc            | 224 +++++++++++++++++++++++++++++++++
 winsup/cygwin/include/cygwin/version.h |   5 +-
 winsup/cygwin/include/ucontext.h       |  12 ++
 winsup/cygwin/ntdll.h                  |   1 +
 winsup/cygwin/release/2.2.0            |  13 ++
 winsup/doc/ChangeLog                   |   7 ++
 winsup/doc/new-features.xml            |  12 ++
 winsup/doc/posix.xml                   |   4 +
 10 files changed, 301 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index db7d723..f2aabf7 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,26 @@
 2015-07-17  Corinna Vinschen  <corinna@vinschen.de>
 
+	* common.din (getcontext): Export.
+	(makecontext): Export.
+	(setcontext): Export.
+	(swapcontext): Export.
+	* exceptions.cc (__unwind_single_frame): New static functions, 64 bit
+	only.
+	(setcontext): New function.
+	(getcontext): New function.
+	(swapcontext): New function.
+	(__cont_link_context): New function.
+	(makecontext): New function.
+	* include/cygwin/version.h (CYGWIN_VERSION_DLL_MAJOR): Bump to 2002.
+	(CYGWIN_VERSION_API_MINOR): Bump.
+	* include/ucontext.h (getcontext): Add prototype.
+	(setcontext): Ditto.
+	(swapcontext): Ditto.
+	(makecontext): Ditto.
+	* ntdll.h (NtContinue): Ditto.
+
+2015-07-17  Corinna Vinschen  <corinna@vinschen.de>
+
 	* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Document the
 	fact that we forgot to bump for sigaltstack and sethostname.
 
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index 644eb2e..e89a6bd 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -503,6 +503,7 @@ getc SIGFE
 getc_unlocked SIGFE
 getchar SIGFE
 getchar_unlocked SIGFE
+getcontext NOSIGFE
 getcwd SIGFE
 getdelim = __getdelim SIGFE
 getdomainname SIGFE
@@ -717,6 +718,7 @@ lsetxattr SIGFE
 lstat SIGFE
 lutimes SIGFE
 madvise = posix_madvise SIGFE
+makecontext NOSIGFE
 mallinfo SIGFE
 malloc SIGFE
 malloc_stats SIGFE
@@ -1054,6 +1056,7 @@ sendmsg = cygwin_sendmsg SIGFE
 sendto = cygwin_sendto SIGFE
 setbuf SIGFE
 setbuffer SIGFE
+setcontext NOSIGFE
 sethostname SIGFE
 setdtablesize SIGFE
 setegid SIGFE
@@ -1199,6 +1202,7 @@ strtoumax = strtoull NOSIGFE
 strupr NOSIGFE
 strxfrm NOSIGFE
 swab NOSIGFE
+swapcontext NOSIGFE
 swprintf SIGFE
 swscanf SIGFE
 symlink SIGFE
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 67df4fe..eea2be3 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -14,6 +14,7 @@ details. */
 #include "miscfuncs.h"
 #include <imagehlp.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <syslog.h>
 #include <wchar.h>
 #include <ucontext.h>
@@ -1863,3 +1864,226 @@ _cygtls::signal_debugger (siginfo_t& si)
       ResumeThread (th);
     }
 }
+
+#ifdef __x86_64__
+static inline void
+__unwind_single_frame (PCONTEXT ctx)
+{
+  /* Amazing, but true:  On 32 bit, RtlCaptureContext returns the context
+     matching the caller of getcontext, so all we have to do is call it.
+     On 64 bit, RtlCaptureContext returns the exact context of its own
+     caller, so we have to unwind virtually by a single frame to get the
+     context of the caller of getcontext. */
+  PRUNTIME_FUNCTION f;
+  ULONG64 imagebase;
+  UNWIND_HISTORY_TABLE hist;
+  DWORD64 establisher;
+  PVOID hdl;
+
+  f = RtlLookupFunctionEntry (ctx->Rip, &imagebase, &hist);
+  if (f)
+    RtlVirtualUnwind (0, imagebase, ctx->Rip, f, ctx, &hdl, &establisher,
+		      NULL);
+  else
+    {
+      ctx->Rip = *(ULONG_PTR *) ctx->Rsp;
+      ctx->Rsp += 8;
+    }
+}
+#endif
+
+extern "C" int
+setcontext (const ucontext_t *ucp)
+{
+  PCONTEXT ctx = (PCONTEXT) &ucp->uc_mcontext;
+  _my_tls.sigmask = ucp->uc_sigmask;
+#ifdef __x86_64__
+  /* Apparently a call to NtContinue works on 64 bit as well, but using
+     RtlRestoreContext is the blessed way. */
+  RtlRestoreContext (ctx, NULL);
+#else
+  NtContinue (ctx, FALSE);
+#endif
+  /* If we got here, something was wrong. */
+  set_errno (EINVAL);
+  return -1;
+}
+
+#ifdef __x86_64__
+
+extern "C" int
+getcontext (ucontext_t *ucp)
+{
+  PCONTEXT ctx = (PCONTEXT) &ucp->uc_mcontext;
+  ctx->ContextFlags = CONTEXT_FULL;
+  RtlCaptureContext (ctx);
+  __unwind_single_frame (ctx);
+  /* Successful getcontext is supposed to return 0.  If we don't set rax to 0
+     here, there's a chance that code like this:
+
+       if (getcontext (&ctx) != 0)
+
+     assumes that getcontext failed after calling setcontext (&ctx).
+     Same goes for eax on 32 bit, see assembler implementation below. */
+  ucp->uc_mcontext.rax = 0;
+  ucp->uc_sigmask = ucp->uc_mcontext.oldmask = _my_tls.sigmask;
+  /* Do not touch any other member of ucontext_t. */
+  return 0;
+}
+
+extern "C" int
+swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
+{
+  PCONTEXT ctx = (PCONTEXT) &oucp->uc_mcontext;
+  ctx->ContextFlags = CONTEXT_FULL;
+  RtlCaptureContext (ctx);
+  __unwind_single_frame (ctx);
+  /* See above. */
+  oucp->uc_mcontext.rax = 0;
+  oucp->uc_sigmask = oucp->uc_mcontext.oldmask = _my_tls.sigmask;
+  return setcontext (ucp);
+}
+
+/* Trampoline function to set the context to uc_link.  The pointer to the
+   address of uc_link is stored in the callee-saved register $rbx.  If uc_link
+   is NULL, call exit. */
+__asm__ ("				\n\
+	.global	__cont_link_context	\n\
+__cont_link_context:			\n\
+	movq	%rbx, %rsp		\n\
+	popq	%rcx			\n\
+	testq	%rcx, %rcx		\n\
+	je	1f			\n\
+	call	setcontext		\n\
+	movq	$0xff, %rcx		\n\
+1:					\n\
+	call	cygwin_exit		\n\
+	nop				\n\
+	");
+
+#else
+
+/* On 32 bit it's crucial to call RtlCaptureContext in a way which makes sure
+   the callee-saved registers, especially $ebx, are not changed by the calling
+   function.  If so, makecontext/__cont_link_context would be broken.
+
+   Both functions are split into the first half in assembler, and the second
+   half in C to allow easy access to _my_tls. */
+
+extern "C" int
+__getcontext (ucontext_t *ucp)
+{
+  ucp->uc_mcontext.eax = 0;
+  ucp->uc_sigmask = ucp->uc_mcontext.oldmask = _my_tls.sigmask;
+  return 0;
+}
+
+__asm__ ("				\n\
+	.global	_getcontext		\n\
+_getcontext:				\n\
+	pushl	%ebp			\n\
+	movl	%esp, %ebp		\n\
+	movl	8(%esp), %eax		\n\
+	pushl	%eax			\n\
+	call	_RtlCaptureContext@4	\n\
+	popl	%ebp			\n\
+	jmp	___getcontext		\n\
+	nop				\n\
+	");
+
+extern "C" int
+__swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
+{
+  oucp->uc_mcontext.eax = 0;
+  oucp->uc_sigmask = oucp->uc_mcontext.oldmask = _my_tls.sigmask;
+  return setcontext (ucp);
+}
+
+__asm__ ("				\n\
+	.global	_swapcontext		\n\
+_swapcontext:				\n\
+	pushl	%ebp			\n\
+	movl	%esp, %ebp		\n\
+	movl	8(%esp), %eax		\n\
+	pushl	%eax			\n\
+	call	_RtlCaptureContext@4	\n\
+	popl	%ebp			\n\
+	jmp	___swapcontext		\n\
+	nop				\n\
+	");
+
+/* Trampoline function to set the context to uc_link.  The pointer to the
+   address of uc_link is stored in the callee-saved register $ebx.  If uc_link
+   is NULL, call exit. */
+__asm__ ("				\n\
+	.global	___cont_link_context	\n\
+___cont_link_context:			\n\
+	movl	%ebx, %esp		\n\
+	movl	(%esp), %eax		\n\
+	testl	%eax, %eax		\n\
+	je	1f			\n\
+	call	_setcontext		\n\
+	movl	$0xff, (%esp)		\n\
+1:					\n\
+	call	_cygwin_exit		\n\
+	nop				\n\
+	");
+#endif
+
+/* makecontext is modelled after GLibc's makecontext.  The stack from uc_stack
+   is prepared so that it starts with a pointer to the linked context uc_link,
+   followed by the arguments to func, and finally at the bottom the "return"
+   address set to __cont_link_context.  In the ucp context, rbx/ebx is set to
+   point to the stack address where the pointer to uc_link is stored.  The
+   requirement to make this work is that rbx/ebx are callee-saved registers
+   per the ABI.  If any function is called which doesn't follow the ABI
+   conventions, e.g. assembler code, this method will break.  But that's ok. */
+extern "C" void
+makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+  extern void __cont_link_context (void);
+  uintptr_t *sp;
+  va_list ap;
+
+  sp = (uintptr_t *) ((uintptr_t) ucp->uc_stack.ss_sp
+				+ ucp->uc_stack.ss_size);
+  sp -= (argc + 1);
+  sp = (uintptr_t *) ((uintptr_t) sp & ~0xf);
+  --sp;
+  sp[0] = (uintptr_t) __cont_link_context;
+  sp[argc + 1] = (uintptr_t) ucp->uc_link;
+#ifdef __x86_64__
+  ucp->uc_mcontext.rip = (uint64_t) func;
+  ucp->uc_mcontext.rbx = (uint64_t) (sp + argc + 1);
+  ucp->uc_mcontext.rsp = (uint64_t) sp;
+#else
+  ucp->uc_mcontext.eip = (uint32_t) func;
+  ucp->uc_mcontext.ebx = (uint32_t) (sp + argc + 1);
+  ucp->uc_mcontext.esp = (uint32_t) sp;
+#endif
+  va_start (ap, argc);
+  for (int i = 0; i < argc; ++i)
+#ifdef __x86_64__
+    switch (i)
+      {
+      case 0:
+	ucp->uc_mcontext.rcx = va_arg (ap, uintptr_t);
+	break;
+      case 1:
+	ucp->uc_mcontext.rdx = va_arg (ap, uintptr_t);
+	break;
+      case 2:
+	ucp->uc_mcontext.r8 = va_arg (ap, uintptr_t);
+	break;
+      case 3:
+	ucp->uc_mcontext.r9 = va_arg (ap, uintptr_t);
+	break;
+      default:
+	sp[i + 1] = va_arg (ap, uintptr_t);
+	break;
+      }
+#else
+    sp[i + 1] = va_arg (ap, uintptr_t);
+#endif
+  va_end (ap);
+}
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 7843136..d909ec3 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -42,7 +42,7 @@ 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 2001
+#define CYGWIN_VERSION_DLL_MAJOR 2002
 #define CYGWIN_VERSION_DLL_MINOR 0
 
       /* Major numbers before CYGWIN_VERSION_DLL_EPOCH are
@@ -469,13 +469,14 @@ details. */
       285: Export wcstold.
       286: Export cabsl, cimagl, creall, finitel, hypotl, sqrtl.
       287: Export issetugid.
+      288: Export getcontext, makecontext, setcontext, swapcontext.
      */
 
      /* 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 287
+#define CYGWIN_VERSION_API_MINOR 288
 
      /* There is also a compatibity version number associated with the
 	shared memory regions.  It is incremented when incompatible
diff --git a/winsup/cygwin/include/ucontext.h b/winsup/cygwin/include/ucontext.h
index 4240597..dd44d75 100644
--- a/winsup/cygwin/include/ucontext.h
+++ b/winsup/cygwin/include/ucontext.h
@@ -11,6 +11,18 @@ details. */
 #ifndef _UCONTEXT_H
 #define _UCONTEXT_H
 
+#include <sys/cdefs.h>
 #include <sys/ucontext.h>
 
+__BEGIN_DECLS
+
+extern int getcontext (ucontext_t *) __attribute__((__nonnull__));
+extern int setcontext (const ucontext_t *) __attribute__((__nonnull__));
+extern int swapcontext (ucontext_t *, const ucontext_t *)
+					__attribute__((__nonnull__));
+extern void makecontext (ucontext_t *, void (*) (void), int, ...)
+					__attribute__((__nonnull__ (1)));
+
+__END_DECLS
+
 #endif /* _UCONTEXT_H */
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index 7d8ccbe..27a50be 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -1258,6 +1258,7 @@ extern "C"
   NTSTATUS NTAPI NtCancelTimer (HANDLE, PBOOLEAN);
   NTSTATUS NTAPI NtClose (HANDLE);
   NTSTATUS NTAPI NtCommitTransaction (HANDLE, BOOLEAN);
+  NTSTATUS NTAPI NtContinue (PCONTEXT, BOOLEAN);
   NTSTATUS NTAPI NtCreateDirectoryObject (PHANDLE, ACCESS_MASK,
 					  POBJECT_ATTRIBUTES);
   NTSTATUS NTAPI NtCreateKey (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG,
diff --git a/winsup/cygwin/release/2.2.0 b/winsup/cygwin/release/2.2.0
new file mode 100644
index 0000000..7831178
--- /dev/null
+++ b/winsup/cygwin/release/2.2.0
@@ -0,0 +1,13 @@
+What's new:
+-----------
+
+- New APIs: getcontext, setcontext, makecontext, swapcontext.
+
+
+What changed:
+-------------
+
+
+Bug Fixes
+---------
+
diff --git a/winsup/doc/ChangeLog b/winsup/doc/ChangeLog
index b452fa9..a4c3036 100644
--- a/winsup/doc/ChangeLog
+++ b/winsup/doc/ChangeLog
@@ -1,3 +1,10 @@
+2015-07-17  Corinna Vinschen  <corinna@vinschen.de>
+
+	* new-features.xml (ov-new2.2): Add new section.  Document getcontext,
+	setcontext, makecontext, swapcontext.
+	* posix.xml (std-deprec): Add getcontext, setcontext, makecontext,
+	swapcontext.
+
 2015-07-05  Jon Turney  <jon.turney@dronecode.org.uk>
 
 	* configure.ac: Add check for DOCBOOK2XTEXI
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index c52574c..85d6ec7 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -4,6 +4,18 @@
 
 <sect1 id="ov-new"><title>What's new and what changed in Cygwin</title>
 
+<sect2 id="ov-new2.2"><title>What's new and what changed in 2.2</title>
+
+<itemizedlist mark="bullet">
+
+<listitem><para>
+New APIs: getcontext, setcontext, makecontext, swapcontext.
+</para></listitem>
+
+</itemizedlist>
+
+</sect2>
+
 <sect2 id="ov-new2.1"><title>What's new and what changed in 2.1</title>
 
 <itemizedlist mark="bullet">
diff --git a/winsup/doc/posix.xml b/winsup/doc/posix.xml
index 8a74f24..112ddc8 100644
--- a/winsup/doc/posix.xml
+++ b/winsup/doc/posix.xml
@@ -1322,6 +1322,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     fcvt			(SUSv3)
     ftime			(SUSv3)
     gcvt			(SUSv3)
+    getcontext			(SUSv3)
     gethostbyaddr		(SUSv3)
     gethostbyname		(SUSv3)
     gethostbyname2		(first defined in BIND 4.9.4)
@@ -1333,6 +1334,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     getwd			(SUSv3)
     h_errno			(SUSv3)
     index			(SUSv3)
+    makecontext			(SUSv3)
     mallinfo			(SVID)
     mallopt			(SVID)
     mktemp			(SUSv3)
@@ -1347,8 +1349,10 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     putw			(SVID)
     rindex			(SUSv3)
     scalb			(SUSv3)
+    setcontext			(SUSv3)
     setutent			(XPG2)
     stime			(SVID)
+    swapcontext			(SUSv3)
     sys_errlist			(BSD)
     sys_nerr			(BSD)
     sys_siglist			(BSD)


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