This is the mail archive of the
cygwin-cvs@cygwin.com
mailing list for the Cygwin project.
[newlib-cygwin] Implement getcontext, setcontext, makecontext, swapcontext
- From: Corinna Vinschen <corinna at sourceware dot org>
- To: cygwin-cvs at sourceware dot org
- Date: 17 Jul 2015 12:31:23 -0000
- Subject: [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)