From 7f9832e774a4b4a5bf7a7cbf31d22d11791fab48 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Mon, 2 Jan 2006 06:15:58 +0000 Subject: * cygload/README: Delete. * cygload/cygload.cc: Move to winsup.api. Add comments from README. * cygload/cygload.h: Move to winsup.api. * cygload/cygload.exp: Move to winsup.api. * Makefile.in: Remove cygload. * winsup.api/winsup.exp: If a .exp file is detected, run it rather than using standard compile. * winsup.api/resethand.c (main): Use printf to print status or expect thinks something is wrong. --- winsup/testsuite/ChangeLog | 13 + winsup/testsuite/Makefile.in | 1 - winsup/testsuite/cygload/Makefile | 36 -- winsup/testsuite/cygload/README | 18 - winsup/testsuite/cygload/cygload.cc | 618 ------------------------------- winsup/testsuite/cygload/cygload.exp | 40 -- winsup/testsuite/cygload/cygload.h | 158 -------- winsup/testsuite/winsup.api/cygload.cc | 628 ++++++++++++++++++++++++++++++++ winsup/testsuite/winsup.api/cygload.exp | 40 ++ winsup/testsuite/winsup.api/cygload.h | 158 ++++++++ winsup/testsuite/winsup.api/resethand.c | 3 +- winsup/testsuite/winsup.api/winsup.exp | 54 +-- 12 files changed, 869 insertions(+), 898 deletions(-) delete mode 100644 winsup/testsuite/cygload/Makefile delete mode 100644 winsup/testsuite/cygload/README delete mode 100644 winsup/testsuite/cygload/cygload.cc delete mode 100644 winsup/testsuite/cygload/cygload.exp delete mode 100644 winsup/testsuite/cygload/cygload.h create mode 100644 winsup/testsuite/winsup.api/cygload.cc create mode 100644 winsup/testsuite/winsup.api/cygload.exp create mode 100644 winsup/testsuite/winsup.api/cygload.h diff --git a/winsup/testsuite/ChangeLog b/winsup/testsuite/ChangeLog index 6ed7c39a1..5fb31a8a3 100644 --- a/winsup/testsuite/ChangeLog +++ b/winsup/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2006-01-02 Christopher Faylor + + * cygload/README: Delete. + * cygload/cygload.cc: Move to winsup.api. Add comments from README. + * cygload/cygload.h: Move to winsup.api. + * cygload/cygload.exp: Move to winsup.api. + * Makefile.in: Remove cygload. + * winsup.api/winsup.exp: If a .exp file is detected, run it rather than + using standard compile. + + * winsup.api/resethand.c (main): Use printf to print status or expect + thinks something is wrong. + 2006-01-01 Christopher Faylor * winsup.api/resethand.c (main): Remove core dump flag from exit diff --git a/winsup/testsuite/Makefile.in b/winsup/testsuite/Makefile.in index cdc96d80b..70bf30c8b 100644 --- a/winsup/testsuite/Makefile.in +++ b/winsup/testsuite/Makefile.in @@ -187,7 +187,6 @@ check: $(TESTSUP_LIB_NAME) $(RUNTIME) cygrun.exe testsuite/site.exp export TCL_LIBRARY ; fi ; \ PATH=$(bupdir)/cygwin:$${PATH} ;\ $(RUNTEST) --tool winsup $(RUNTESTFLAGS) ;\ - $(RUNTEST) --tool cygload $(RUNTESTFLAGS) cygrun.o: cygrun.c $(CC) $(MINGW_CFLAGS) -o $@ -c $< diff --git a/winsup/testsuite/cygload/Makefile b/winsup/testsuite/cygload/Makefile deleted file mode 100644 index e88dde3cd..000000000 --- a/winsup/testsuite/cygload/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# Makefile for cygload - -### -### MinGW options -### -CC = gcc -CFLAGS = -mno-cygwin -Wall -LINKFLAGS = -lstdc++ -Wl,-e,_cygloadCRTStartup@0 - -### -### MSVC options -### -ifndef MSVCDir -MSVCDir = C:/cygwin/usr/local/tools/i686_win32/vc7/Vc7 -endif - -CL = $(MSVCDir)/bin/cl -# If you want to look at the assembly, add "/Famsvc-cygload.asm /FAs". -MSVCCFLAGS = /nologo /GX /MDd /Zi /W4 /TP -MSVCINCLUDES = /I $(MSVCDir)/include /I $(MSVCDir)/PlatformSDK/Include -# Using /ENTRY seems to automatically invoke /NODEFAULTLIBS. -MSVCLIBS = /link /LIBPATH:$(MSVCDir)/lib /LIBPATH:$(MSVCDir)/PlatformSDK/lib \ - /ENTRY:cygloadCRTStartup uuid.lib msvcprtd.lib msvcrtd.lib \ - oldnames.lib kernel32.lib - -all: mingw-cygload.exe - -mingw-cygload.exe: cygload.cc cygload.h - $(CC) $(CFLAGS) $< -o $@ $(LINKFLAGS) - -msvc-cygload.exe: cygload.cc cygload.h - $(CL) $(MSVCCFLAGS) $(MSVCINCLUDES) $< /o $@ $(MSVCLIBS) - -clean: - rm -f msvc-cygload.exe msvc-cygload.ilk cygload.obj \ - msvc-cygload.pdb vc70.pdb mingw-cygload.exe diff --git a/winsup/testsuite/cygload/README b/winsup/testsuite/cygload/README deleted file mode 100644 index a61f73bee..000000000 --- a/winsup/testsuite/cygload/README +++ /dev/null @@ -1,18 +0,0 @@ -cygload demonstrates how to dynamically load cygwin1.dll. The default -build uses MinGW to compile it; the Makefile also shows how to build -it using the Microsoft compiler. - -By default, the program will silently test basic functionality: - * Making space on the stack for cygtls - * Loading and initializing cygwin1.dll - * Path translation - * Error handling - * Signal handling - -Command line parameters are: - - -v Verbose output - -testinterrupts Pause for 30 seconds to allow testing command line - interrupts (^C) - -cygwin xxx Specifies an alternative DLL to load instead of - cygwin1.dll. diff --git a/winsup/testsuite/cygload/cygload.cc b/winsup/testsuite/cygload/cygload.cc deleted file mode 100644 index 0febf326e..000000000 --- a/winsup/testsuite/cygload/cygload.cc +++ /dev/null @@ -1,618 +0,0 @@ -// cygload.cpp -// -// Copyright 2005, Red Hat, Inc. -// -// Written by Max Kaehn -// -// This software is a copyrighted work licensed under the terms of the -// Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. -// -// Note that dynamically linking to cygwin1.dll automatically places your code -// under the GPL unless you purchase a Cygwin Contract with Red Hat, Inc. -// See http://www.redhat.com/software/cygwin/ for more information. - - -// Options for this program: -// -v Verbose output. Normal operation is entirely silent, -// save for errors. -// -testinterrupts Pauses the program for 30 seconds so you can demonstrate -// that it handles ^C properly. -// -cygwin Name of DLL to load. Defaults to "cygwin1.dll". - -#include "cygload.h" -#include -#include -#include -#include // for ENOENT -#include -#include - -using std::cout; -using std::cerr; -using std::endl; -using std::string; - -cygwin::padding *cygwin::padding::_main = NULL; -DWORD cygwin::padding::_mainTID = 0; - -// A few cygwin constants. -static const int SIGHUP = 1; -static const int SIGINT = 2; -static const int SIGTERM = 15; // Cygwin won't deliver this one to us; - // expect unadorned "kill" to just kill - // your process. -static const int SIGSTOP = 17; // Cygwin insists on delivering SIGSTOP to - // the main thread. If your main thread - // is not interruptible, you'll miss the - // signal and ignore the request to suspend. -static const int SIGTSTP = 18; // ^Z on a tty. -static const int SIGCONT = 19; // Resume a stopped process. -static const int SIGUSR1 = 30; -static const int SIGUSR2 = 31; - -// Using *out instead of cout. In verbose mode, out == &cout. -static std::ostream *out = NULL; - -cygwin::padding::padding () -{ - _main = this; - _mainTID = GetCurrentThreadId (); - - _end = _padding + sizeof (_padding); - char *stackbase; -#ifdef __GNUC__ - __asm__ ( - "movl %%fs:4, %0" - :"=r"(stackbase) - ); -#else - __asm - { - mov eax, fs:[4]; - mov stackbase, eax; - } -#endif - _stackbase = stackbase; - - // We've gotten as close as we can to the top of the stack. Even - // subverting the entry point, though, still doesn't get us there-- I'm - // getting 64 bytes in use before the entry point. So we back up the data - // there and restore it when the destructor is called: - if ((_stackbase - _end) != 0) - { - size_t delta = (_stackbase - _end); - - _backup.resize (delta); - - memcpy (&(_backup[0]), _end, delta); - } -} - -cygwin::padding::~padding () -{ - _main = NULL; - - if (_backup.size ()) - { - memcpy (_end, &(_backup[0]), _backup.size ()); - } -} - -void -cygwin::padding::check () -{ - if (_main == NULL) - throw std::runtime_error ("No padding declared!"); - if (_mainTID != GetCurrentThreadId ()) - throw std::runtime_error ("You need to initialize cygwin::connector " - "in the same thread in which you declared the " - "padding."); - - if (_main->_backup.size ()) - *out << "Warning! Stack base is " - << static_cast(_main->_stackbase) - << ". padding ends at " << static_cast(_main->_end) - << ". Delta is " << (_main->_stackbase - _main->_end) - << ". Stack variables could be overwritten!" << endl; -} - -cygwin::connector::connector (const char *dll) -{ - // This will throw if padding is not in place. - padding::check (); - - *out << "Loading " << dll << "..." << endl; - - // This should call init.cc:dll_entry() with DLL_PROCESS_ATTACH, - // which calls dll_crt0_0(). - if ((_library = LoadLibrary (dll)) == NULL) - throw windows_error ("LoadLibrary", dll); - - *out << "Initializing cygwin..." << endl; - - // This calls dcrt0.cc:cygwin_dll_init(), which calls dll_crt0_1(), - // which will, among other things: - // * spawn the cygwin signal handling thread from sigproc_init() - // * initialize the thread-local storage for this thread and overwrite - // the first 4K of the stack - void (*cyginit) (); - get_symbol ("cygwin_dll_init", cyginit); - (*cyginit) (); - - *out << "Loading symbols..." << endl; - - // Pick up the function pointers for the basic infrastructure. - get_symbol ("__errno", _errno); - get_symbol ("strerror", _strerror); - get_symbol ("cygwin_conv_to_full_posix_path", _conv_to_full_posix_path); - get_symbol ("cygwin_conv_to_full_win32_path", _conv_to_full_win32_path); - - // Note that you need to be running an interruptible cygwin function if - // you want to receive signals. You can use the standard signal() - // mechanism if you're willing to have your main thread spend all its time - // in interruptible cygwin functions like sleep(). Christopher Faylor - // cautions that this solution "could be slightly racy": if a second - // signal comes in before the first one is done processing, the thread - // won't be back in sigwait() to catch it. - *out << "Spawning signal handling thread..." << endl; - - _waiting_for_signals = true; - _signal_thread_done = false; - InitializeCriticalSection (&_thread_mutex); - - DWORD tid; - - _signal_thread = CreateThread (NULL, // Default security. - 32768, // Adjust the stack size as - // appropriate for what your signal - // handler needs in order to run, and - // then add 4K for cygtls. - &signal_thread, // Function to call - this, // Context - 0, // Flags - &tid); // Thread ID - - if (_signal_thread == NULL) - throw windows_error ("CreateThread", "signal_thread"); -} - -cygwin::connector::~connector () -{ - try - { - // First, shut down signal handling. - int (*raze) (int); - int (*pthread_join) (void *, void **); - - get_symbol ("raise", raze); - get_symbol ("pthread_join", pthread_join); - - // Tell the listener to shut down... - _waiting_for_signals = false; - int err = 0; - EnterCriticalSection (&_thread_mutex); - if (!_signal_thread_done) - err = raze (SIGUSR2); - LeaveCriticalSection (&_thread_mutex); - if (err) - cerr << error (this, "raise", "SIGUSR2").what () << endl; - // ...and get the thread to join. - if (!CloseHandle (_signal_thread)) - throw windows_error ("CloseHandle", "signal_thread"); - - // This should call init.cc:dll_entry() with DLL_PROCESS_DETACH. - if (!FreeLibrary (_library)) - throw windows_error ("FreeLibrary", "cygwin1.dll"); - } - catch (std::exception &x) - { - cerr << x.what () << endl; - } -} - -DWORD WINAPI -cygwin::connector::signal_thread (void *param) -{ - connector *that = reinterpret_cast < connector * > (param); - - try - { - that->await_signal (); - } - catch (std::exception &x) - { - cerr << "signal_thread caught " << x.what () << endl; - return 0; - } - return 0; -} - -void -cygwin::connector::await_signal () -{ - // Wait for signals. - unsigned long sigset[32]; - int sig; - int (*empty) (void *); - int (*add) (void *, int); - int (*wait) (void *, int *); - - get_symbol ("sigemptyset", empty); - get_symbol ("sigaddset", add); - get_symbol ("sigwait", wait); - - empty (sigset); - add (sigset, SIGHUP); - add (sigset, SIGINT); -// add (sigset, SIGSTOP); -// add (sigset, SIGTSTP); // I can't get this to suspend properly, so - // I'll leave it up to chance that the main - // thread is interruptible. - add (sigset, SIGUSR1); - add (sigset, SIGUSR2); - - while (_waiting_for_signals) - { - int err = wait (sigset, &sig); - if (err) - cerr << error (this, "sigwait").what () << endl; - else - *out << "Received signal " << sig << "." << endl; - switch (sig) - { - case SIGUSR2: - if (!_waiting_for_signals) - { - // SIGUSR2 is how ~connector wakes this thread - goto done; - } - break; - default: - break; - } - handle_signals (sig); - } -done: - EnterCriticalSection (&_thread_mutex); - _signal_thread_done = true; - LeaveCriticalSection (&_thread_mutex); - - *out << "await_signal done." << endl; -} - -cygwin::connector::signal_handler * -cygwin::connector::set_handler (int signal, signal_handler *handler) -{ - signal_handler *retval = _signal_handlers[signal]; - - if (handler == NULL) - _signal_handlers.erase (signal); - else - _signal_handlers[signal] = handler; - - return retval; -} - -void -cygwin::connector::handle_signals (int sig) -{ - callback_list::iterator h = _signal_handlers.find (sig); - - if (h != _signal_handlers.end ()) - { - try - { - signal_handler *handler = h->second; - (*handler) (sig); - return; - } - catch (std::exception &x) - { - cerr << "cygwin::connector::handle_signals caught " - << x.what () << "!" << endl; - return; - } - } - - cerr << "No handler for signal " << sig << "!" << endl; -} - -int -cygwin::connector::err_no () const -{ - int *e = (*_errno) (); - if (e == NULL) - { - return -1; - } - return *e; -} - -string -cygwin::connector::str_error (int err_no) const -{ - string retval; - - const char *s = (*_strerror) (err_no); - if (s != NULL) - { - retval = s; - } - else - { - std::ostringstream o; - o << "Unexpected errno " << err_no; - retval = o.str (); - } - - return retval; -} - -string -cygwin::connector::unix_path (const string &windows) const -{ - char buf[MAX_PATH]; - - _conv_to_full_posix_path (windows.c_str (), buf); - - return string (buf); -} - -string -cygwin::connector::win_path (const string &unix) const -{ - char buf[MAX_PATH]; - - _conv_to_full_win32_path (unix.c_str (), buf); - - return string (buf); -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -string -cygwin::error::format (cygwin::connector *c, - int err_no, const char *message, const char *detail) -{ - std::ostringstream ret; - - ret << message; - if (detail) - { - ret << "(" << detail << ")"; - } - ret << ": " << c->str_error (err_no); - - return ret.str (); -} - -string -windows_error::format (DWORD error, const char *message, const char *detail) -{ - std::ostringstream ret; - char buf[512]; - DWORD bytes; - - ret << message; - if (detail) - ret << "(" << detail << ")"; - ret << ": "; - - bytes = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, error, - MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), - buf, sizeof (buf), 0); - - if (bytes == 0) - ret << "Unexpected Windows error " << error; - else - { - // Remove trailing whitespace - char *p = buf + bytes - 1; - while (isspace (*p)) - *p-- = '\0'; - ret << buf << " (" << error << ")"; - } - - return ret.str (); -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -extern "C" int mainCRTStartup (); - -// This just pushes 4K onto the stack, backs up the original stack, and -// jumps into the regular startup code. This avoids having to worry about -// backing up argc and argv. -extern "C" int __stdcall -cygloadCRTStartup () -{ - cygwin::padding padding; - return mainCRTStartup (); -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -static void -hangup (int sig) -{ - cout << "Hangup (" << sig << ")." << endl; -} - -static void -interrupt (int sig) -{ - cerr << "Interrupt (" << sig << ")!" << endl; - exit (0); -} - -static int caught = false; - -static void -catch_signal (int) -{ - *out << "Signals are working." << endl; - caught = true; -} - -int -main (int argc, char *argv[]) -{ - // If you do not want to use cygloadCRTStartup() as an entry point, - // uncomment this line, but be sure to have *everything* you want - // from the stack below it backed up before you call the - // constructor for cygwin::connector. - //cygwin::padding padding; - - std::ostringstream output; - bool verbose = false, testinterrupts = false; - const char *dll = "cygwin1.dll"; - - out = &output; - - for (int i = 1; i < argc; ++i) - { - string arg = string (argv[i]); - - if (arg == "-v") - { - verbose = true; - out = &cout; - } - else if (arg == "-testinterrupts") - testinterrupts = true; - else if (arg == "-cygwin") - { - if (i+1 >= argc) - { - cerr << "Need to supply an argument with -cygwin." << endl; - return 255; - } - dll = argv[++i]; - } - } - - - try - { - *out << "Connecting to cygwin..." << endl; - cygwin::connector cygwin (dll); - *out << "Successfully connected." << endl; - - string result = cygwin.str_error (ENOENT); - - if (result != "No such file or directory") - { - cerr << "strerror(ENOENT) returned \"" - << result - << "\" instead of \"No such file or directory\"!" - << endl; - return 1; - } - else if (verbose) - { - *out << "strerror(ENOENT) = " << result << endl; - } - - // Path conversion: from cygwin to Windows... - result = cygwin.win_path ("/usr"); - struct _stat statbuf; - if (::_stat (result.c_str (), &statbuf) < 0) - { - cerr << "stat(\"" << result << "\") failed!" << endl; - return 2; - } - else if (verbose) - { - *out << "/usr == " << result << endl; - } - - // ...and back: - char buf[MAX_PATH], scratch[256]; - GetSystemDirectory (buf, sizeof(buf)); - int (*cygstat) (const char *, void *); - cygwin.get_symbol ("stat", cygstat); - - if (cygstat (buf, scratch) < 0) - { - cerr << "cygwin stat(\"" << buf << "\") failed!" << endl; - return 3; - } - else if (verbose) - { - *out << buf << " == " << cygwin.unix_path(buf) << endl; - } - - // Test error handling. This should output - // "open(/potrzebie/furshlugginer): No such file or directory" - { - int (*cygopen) (const char *, int); - cygwin.get_symbol ("open", cygopen); - - if (cygopen ("/potrzebie/furshlugginer", 0 /* O_RDONLY */ ) < 0) - { - int err = cygwin.err_no (); - if (err != ENOENT) - { - cerr << "cygwin open(\"/potrzebie/furshlugginer\", " - "O_RDONLY): expected to fail with ENOENT, got " - << err << "!" << endl; - return 4; - } - if (verbose) - *out << cygwin::error (&cygwin, "open", - "/potrzebie/furshlugginer").what () - << endl; - } - else - { - cerr << "/potrzebie/furshlugginer should not exist!" - << endl; - return 5; - } - } - - // And signal handling: - std::pointer_to_unary_function < int , void > h1 (&hangup); - std::pointer_to_unary_function < int , void > h2 (&interrupt); - std::pointer_to_unary_function < int , void > h3 (&catch_signal); - cygwin.set_handler (SIGHUP, &h1); - cygwin.set_handler (SIGINT, &h2); - cygwin.set_handler (SIGUSR1, &h3); - - // Make sure the signal handler thread has had time to start... - Sleep (100); - // Send a test signal to set "caught" to true... - int (*raze) (int); - cygwin.get_symbol ("raise", raze); - raze (SIGUSR1); - // And give the thread time to wait for the shutdown signal. - Sleep (100); - - if (testinterrupts) - { - // This is a worst case scenario for testing interrupts: the - // main thread is in a long-duration Windows API call. This - // makes the main thread uninterruptible; cygwin will retry - // 20 times, with a low_priority_sleep(0) between each try. - cout << "Sleeping for 30 seconds, waiting for a signal..." << endl; - Sleep (30000); - cout << "Done waiting." << endl; - } - } - catch (std::exception &x) - { - cerr << x.what () << endl; - return 2; - } - - if (caught) - return 0; - else - { - cerr << "Never received SIGUSR1." << endl; - return 1; - } -} diff --git a/winsup/testsuite/cygload/cygload.exp b/winsup/testsuite/cygload/cygload.exp deleted file mode 100644 index a07a549f9..000000000 --- a/winsup/testsuite/cygload/cygload.exp +++ /dev/null @@ -1,40 +0,0 @@ -source "site.exp" - -if { ! [isnative] } { - verbose "skipping cygload because it's not native \"$target_triplet\" != \"$build_triplet\"" - return -} - -proc ws_spawn {cmd args} { - global rv - verbose "running $cmd\n" - set rv {} - # First item in rv is the return code, second item is the message - lappend rv [catch "exec $cmd" message] $message - verbose send "catchCode = $rv\n" -} - -ws_spawn "gcc -mno-cygwin $srcdir/$subdir/cygload.cc -o mingw-cygload.exe -lstdc++ -Wl,-e,_cygloadCRTStartup@0" - -if { $rv != {0 {}} } { - verbose -log "$rv" - fail "cygload (compile)" -} else { - if { $verbose } { - set redirect_output "./mingw-cygwin.log" - } else { - set redirect_output /dev/null - } - set windows_runtime_root [exec cygpath -m $runtime_root] - ws_spawn "./mingw-cygload.exe -cygwin $windows_runtime_root/cygwin0.dll > $redirect_output" - if { $rv != {0 {}} } { - verbose -log "cygload: $rv" - fail "cygload (execute)" - } else { - pass "cygload" - } - catch { file delete "mingw-cygload.exe" } err - if { $err != "" } { - note "error deleting mingw-cygload.exe: $err" - } -} diff --git a/winsup/testsuite/cygload/cygload.h b/winsup/testsuite/cygload/cygload.h deleted file mode 100644 index dfe9d0f78..000000000 --- a/winsup/testsuite/cygload/cygload.h +++ /dev/null @@ -1,158 +0,0 @@ -// cygload.h -*- C++ -*- -// -// Copyright 2005, Red Hat, Inc. -// -// Written by Max Kaehn -// -// This software is a copyrighted work licensed under the terms of the -// Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. -// -// Note that dynamically linking to cygwin1.dll automatically places your code -// under the GPL unless you purchase a Cygwin Contract with Red Hat, Inc. -// See http://www.redhat.com/software/cygwin/ for more information. - -// This program has large numbers of progress messages so as to provide -// maximum information about crash locations for anyone without access to -// a Microsoft debugger. - - -// This file contains the basic infrastructure for connecting an MSVC -// process to Cygwin. - -#ifndef __CYGLOAD_H__ -#define __CYGLOAD_H__ - -#include // for GetProcAddress() -#include // for pointer_to_unary_function -#include // for runtime_error -#include -#include -#include - -// Convert GetLastError() to a human-readable STL exception. -class windows_error : public std::runtime_error -{ -public: - windows_error (const char *message, const char *detail = NULL) - : runtime_error (format (GetLastError (), message, detail)) { } - windows_error(DWORD error, const char *message, const char *detail = NULL) - : runtime_error (format (error, message, detail)) { } - - static std::string format (DWORD error, const char *message, - const char *detail); -}; - -namespace cygwin -{ - - // Cygwin keeps important thread-local information at the top of the - // stack. Its DllMain-equivalent will do the right thing for any threads - // you spawn, but you need to declare one of these as the very first thing - // in your main() function so horrible things won't happen when cygwin - // overwrites your stack. This will back up the data that will be - // overwritten and restore it when the destructor is called. - class padding { - public: - padding (); - ~padding (); - - // Verifies that padding has been declared. - static void check (); - - private: - std::vector< char > _backup; - char *_stackbase, *_end; - - // gdb reports sizeof(_cygtls) == 3964 at the time of this writing. - // This is at the end of the object so it'll be toward the bottom - // of the stack when it gets declared. - char _padding[4096]; - - static padding *_main; - static DWORD _mainTID; - }; - - // This hooks your application up to cygwin: it loads cygwin1.dll, - // initializes it properly, grabs some important symbols, and - // spawns a thread to let you receive signals from cygwin. - class connector { - public: - connector (const char *dll = "cygwin1.dll"); - ~connector (); - - // A wrapper around GetProcAddress() for fetching symbols from the - // cygwin DLL. Can throw windows_error. - template < class T > void get_symbol (const char *name, T &fn) const; - - // Wrappers for errno() and strerror(). - int err_no () const; - std::string str_error (int) const; - - // Converting between the worlds of Windows and Cygwin. - std::string unix_path (const std::string &windows) const; - std::string win_path (const std::string &unix) const; - - private: - HMODULE _library; - - int *(*_errno) (); - const char *(*_strerror) (int); - void (*_conv_to_full_posix_path) (const char *, char *); - void (*_conv_to_full_win32_path) (const char *, char *); - - public: - // The constructor will automatically hook you up for receiving - // cygwin signals. Just specify a signal and pass in a signal_handler. - typedef std::pointer_to_unary_function signal_handler; - signal_handler *set_handler (int signal, signal_handler *); - - private: - // Cygwin signals can only be received in threads that are calling - // interruptible functions or otherwise ready to intercept signals, so - // we spawn a thread that does nothing but call sigwait(). - - // This is the entry point: - static DWORD WINAPI signal_thread (void *); - // It runs this: - void await_signal (); - // And will execute this on receipt of any signal for which it's - // registered: - void handle_signals (int); - - HANDLE _signal_thread; - bool _waiting_for_signals, _signal_thread_done; - CRITICAL_SECTION _thread_mutex; - - typedef std::map< int, signal_handler * > callback_list; - callback_list _signal_handlers; - }; - - template void connector::get_symbol (const char *name, - T &symbol) const - { - FARPROC retval = NULL; - - retval = GetProcAddress (_library, name); - - if (retval == NULL) - throw windows_error ("GetProcAddress", name); - - symbol = reinterpret_cast < T > (retval); - } - - // cygwin::error converts errno to a human-readable exception. - class error : public std::runtime_error - { - public: - error (connector *c, const char *function, const char *detail = NULL) - : runtime_error (format (c, c->err_no (), function, detail)) { } - error (connector *c, int err_no, const char *function, - const char *detail = NULL) - : runtime_error (format (c, err_no, function, detail)) { } - - static std::string format(connector *c, int err_no, - const char *message, const char *detail); - }; -} - -#endif // __CYGLOAD_H__ diff --git a/winsup/testsuite/winsup.api/cygload.cc b/winsup/testsuite/winsup.api/cygload.cc new file mode 100644 index 000000000..bdbbcd1a3 --- /dev/null +++ b/winsup/testsuite/winsup.api/cygload.cc @@ -0,0 +1,628 @@ +/* cygload.cc + + Copyright 2005, 2006 Red Hat, Inc. + + Written by Max Kaehn + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. + + Note that dynamically linking to cygwin1.dll automatically places your code + under the GPL unless you purchase a Cygwin Contract with Red Hat, Inc. + See http://www.redhat.com/software/cygwin/ for more information. + + cygload demonstrates how to dynamically load cygwin1.dll. The default + build uses MinGW to compile it; the Makefile also shows how to build + it using the Microsoft compiler. + + By default, the program will silently test basic functionality: + * Making space on the stack for cygtls + * Loading and initializing cygwin1.dll + * Path translation + * Error handling + * Signal handling + + Options for this program: + -v Verbose output. Normal operation is entirely silent, + save for errors. + -testinterrupts Pauses the program for 30 seconds so you can demonstrate + that it handles ^C properly. + -cygwin Name of DLL to load. Defaults to "cygwin1.dll". */ + +#include "cygload.h" +#include +#include +#include +#include // for ENOENT +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::string; + +cygwin::padding *cygwin::padding::_main = NULL; +DWORD cygwin::padding::_mainTID = 0; + +// A few cygwin constants. +static const int SIGHUP = 1; +static const int SIGINT = 2; +static const int SIGTERM = 15; // Cygwin won't deliver this one to us; + // expect unadorned "kill" to just kill + // your process. +static const int SIGSTOP = 17; // Cygwin insists on delivering SIGSTOP to + // the main thread. If your main thread + // is not interruptible, you'll miss the + // signal and ignore the request to suspend. +static const int SIGTSTP = 18; // ^Z on a tty. +static const int SIGCONT = 19; // Resume a stopped process. +static const int SIGUSR1 = 30; +static const int SIGUSR2 = 31; + +// Using *out instead of cout. In verbose mode, out == &cout. +static std::ostream *out = NULL; + +cygwin::padding::padding () +{ + _main = this; + _mainTID = GetCurrentThreadId (); + + _end = _padding + sizeof (_padding); + char *stackbase; +#ifdef __GNUC__ + __asm__ ( + "movl %%fs:4, %0" + :"=r"(stackbase) + ); +#else + __asm + { + mov eax, fs:[4]; + mov stackbase, eax; + } +#endif + _stackbase = stackbase; + + // We've gotten as close as we can to the top of the stack. Even + // subverting the entry point, though, still doesn't get us there-- I'm + // getting 64 bytes in use before the entry point. So we back up the data + // there and restore it when the destructor is called: + if ((_stackbase - _end) != 0) + { + size_t delta = (_stackbase - _end); + + _backup.resize (delta); + + memcpy (&(_backup[0]), _end, delta); + } +} + +cygwin::padding::~padding () +{ + _main = NULL; + + if (_backup.size ()) + { + memcpy (_end, &(_backup[0]), _backup.size ()); + } +} + +void +cygwin::padding::check () +{ + if (_main == NULL) + throw std::runtime_error ("No padding declared!"); + if (_mainTID != GetCurrentThreadId ()) + throw std::runtime_error ("You need to initialize cygwin::connector " + "in the same thread in which you declared the " + "padding."); + + if (_main->_backup.size ()) + *out << "Warning! Stack base is " + << static_cast(_main->_stackbase) + << ". padding ends at " << static_cast(_main->_end) + << ". Delta is " << (_main->_stackbase - _main->_end) + << ". Stack variables could be overwritten!" << endl; +} + +cygwin::connector::connector (const char *dll) +{ + // This will throw if padding is not in place. + padding::check (); + + *out << "Loading " << dll << "..." << endl; + + // This should call init.cc:dll_entry() with DLL_PROCESS_ATTACH, + // which calls dll_crt0_0(). + if ((_library = LoadLibrary (dll)) == NULL) + throw windows_error ("LoadLibrary", dll); + + *out << "Initializing cygwin..." << endl; + + // This calls dcrt0.cc:cygwin_dll_init(), which calls dll_crt0_1(), + // which will, among other things: + // * spawn the cygwin signal handling thread from sigproc_init() + // * initialize the thread-local storage for this thread and overwrite + // the first 4K of the stack + void (*cyginit) (); + get_symbol ("cygwin_dll_init", cyginit); + (*cyginit) (); + + *out << "Loading symbols..." << endl; + + // Pick up the function pointers for the basic infrastructure. + get_symbol ("__errno", _errno); + get_symbol ("strerror", _strerror); + get_symbol ("cygwin_conv_to_full_posix_path", _conv_to_full_posix_path); + get_symbol ("cygwin_conv_to_full_win32_path", _conv_to_full_win32_path); + + // Note that you need to be running an interruptible cygwin function if + // you want to receive signals. You can use the standard signal() + // mechanism if you're willing to have your main thread spend all its time + // in interruptible cygwin functions like sleep(). Christopher Faylor + // cautions that this solution "could be slightly racy": if a second + // signal comes in before the first one is done processing, the thread + // won't be back in sigwait() to catch it. + *out << "Spawning signal handling thread..." << endl; + + _waiting_for_signals = true; + _signal_thread_done = false; + InitializeCriticalSection (&_thread_mutex); + + DWORD tid; + + _signal_thread = CreateThread (NULL, // Default security. + 32768, // Adjust the stack size as + // appropriate for what your signal + // handler needs in order to run, and + // then add 4K for cygtls. + &signal_thread, // Function to call + this, // Context + 0, // Flags + &tid); // Thread ID + + if (_signal_thread == NULL) + throw windows_error ("CreateThread", "signal_thread"); +} + +cygwin::connector::~connector () +{ + try + { + // First, shut down signal handling. + int (*raze) (int); + int (*pthread_join) (void *, void **); + + get_symbol ("raise", raze); + get_symbol ("pthread_join", pthread_join); + + // Tell the listener to shut down... + _waiting_for_signals = false; + int err = 0; + EnterCriticalSection (&_thread_mutex); + if (!_signal_thread_done) + err = raze (SIGUSR2); + LeaveCriticalSection (&_thread_mutex); + if (err) + cerr << error (this, "raise", "SIGUSR2").what () << endl; + // ...and get the thread to join. + if (!CloseHandle (_signal_thread)) + throw windows_error ("CloseHandle", "signal_thread"); + + // This should call init.cc:dll_entry() with DLL_PROCESS_DETACH. + if (!FreeLibrary (_library)) + throw windows_error ("FreeLibrary", "cygwin1.dll"); + } + catch (std::exception &x) + { + cerr << x.what () << endl; + } +} + +DWORD WINAPI +cygwin::connector::signal_thread (void *param) +{ + connector *that = reinterpret_cast < connector * > (param); + + try + { + that->await_signal (); + } + catch (std::exception &x) + { + cerr << "signal_thread caught " << x.what () << endl; + return 0; + } + return 0; +} + +void +cygwin::connector::await_signal () +{ + // Wait for signals. + unsigned long sigset[32]; + int sig; + int (*empty) (void *); + int (*add) (void *, int); + int (*wait) (void *, int *); + + get_symbol ("sigemptyset", empty); + get_symbol ("sigaddset", add); + get_symbol ("sigwait", wait); + + empty (sigset); + add (sigset, SIGHUP); + add (sigset, SIGINT); +// add (sigset, SIGSTOP); +// add (sigset, SIGTSTP); // I can't get this to suspend properly, so + // I'll leave it up to chance that the main + // thread is interruptible. + add (sigset, SIGUSR1); + add (sigset, SIGUSR2); + + while (_waiting_for_signals) + { + int err = wait (sigset, &sig); + if (err) + cerr << error (this, "sigwait").what () << endl; + else + *out << "Received signal " << sig << "." << endl; + switch (sig) + { + case SIGUSR2: + if (!_waiting_for_signals) + { + // SIGUSR2 is how ~connector wakes this thread + goto done; + } + break; + default: + break; + } + handle_signals (sig); + } +done: + EnterCriticalSection (&_thread_mutex); + _signal_thread_done = true; + LeaveCriticalSection (&_thread_mutex); + + *out << "await_signal done." << endl; +} + +cygwin::connector::signal_handler * +cygwin::connector::set_handler (int signal, signal_handler *handler) +{ + signal_handler *retval = _signal_handlers[signal]; + + if (handler == NULL) + _signal_handlers.erase (signal); + else + _signal_handlers[signal] = handler; + + return retval; +} + +void +cygwin::connector::handle_signals (int sig) +{ + callback_list::iterator h = _signal_handlers.find (sig); + + if (h != _signal_handlers.end ()) + { + try + { + signal_handler *handler = h->second; + (*handler) (sig); + return; + } + catch (std::exception &x) + { + cerr << "cygwin::connector::handle_signals caught " + << x.what () << "!" << endl; + return; + } + } + + cerr << "No handler for signal " << sig << "!" << endl; +} + +int +cygwin::connector::err_no () const +{ + int *e = (*_errno) (); + if (e == NULL) + { + return -1; + } + return *e; +} + +string +cygwin::connector::str_error (int err_no) const +{ + string retval; + + const char *s = (*_strerror) (err_no); + if (s != NULL) + { + retval = s; + } + else + { + std::ostringstream o; + o << "Unexpected errno " << err_no; + retval = o.str (); + } + + return retval; +} + +string +cygwin::connector::unix_path (const string &windows) const +{ + char buf[MAX_PATH]; + + _conv_to_full_posix_path (windows.c_str (), buf); + + return string (buf); +} + +string +cygwin::connector::win_path (const string &unix) const +{ + char buf[MAX_PATH]; + + _conv_to_full_win32_path (unix.c_str (), buf); + + return string (buf); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +string +cygwin::error::format (cygwin::connector *c, + int err_no, const char *message, const char *detail) +{ + std::ostringstream ret; + + ret << message; + if (detail) + { + ret << "(" << detail << ")"; + } + ret << ": " << c->str_error (err_no); + + return ret.str (); +} + +string +windows_error::format (DWORD error, const char *message, const char *detail) +{ + std::ostringstream ret; + char buf[512]; + DWORD bytes; + + ret << message; + if (detail) + ret << "(" << detail << ")"; + ret << ": "; + + bytes = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, error, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, sizeof (buf), 0); + + if (bytes == 0) + ret << "Unexpected Windows error " << error; + else + { + // Remove trailing whitespace + char *p = buf + bytes - 1; + while (isspace (*p)) + *p-- = '\0'; + ret << buf << " (" << error << ")"; + } + + return ret.str (); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +extern "C" int mainCRTStartup (); + +// This just pushes 4K onto the stack, backs up the original stack, and +// jumps into the regular startup code. This avoids having to worry about +// backing up argc and argv. +extern "C" int __stdcall +cygloadCRTStartup () +{ + cygwin::padding padding; + return mainCRTStartup (); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void +hangup (int sig) +{ + cout << "Hangup (" << sig << ")." << endl; +} + +static void +interrupt (int sig) +{ + cerr << "Interrupt (" << sig << ")!" << endl; + exit (0); +} + +static int caught = false; + +static void +catch_signal (int) +{ + *out << "Signals are working." << endl; + caught = true; +} + +int +main (int argc, char *argv[]) +{ + // If you do not want to use cygloadCRTStartup() as an entry point, + // uncomment this line, but be sure to have *everything* you want + // from the stack below it backed up before you call the + // constructor for cygwin::connector. + //cygwin::padding padding; + + std::ostringstream output; + bool verbose = false, testinterrupts = false; + const char *dll = "cygwin1.dll"; + + out = &output; + + for (int i = 1; i < argc; ++i) + { + string arg = string (argv[i]); + + if (arg == "-v") + { + verbose = true; + out = &cout; + } + else if (arg == "-testinterrupts") + testinterrupts = true; + else if (arg == "-cygwin") + { + if (i+1 >= argc) + { + cerr << "Need to supply an argument with -cygwin." << endl; + return 255; + } + dll = argv[++i]; + } + } + + + try + { + *out << "Connecting to cygwin..." << endl; + cygwin::connector cygwin (dll); + *out << "Successfully connected." << endl; + + string result = cygwin.str_error (ENOENT); + + if (result != "No such file or directory") + { + cerr << "strerror(ENOENT) returned \"" + << result + << "\" instead of \"No such file or directory\"!" + << endl; + return 1; + } + else if (verbose) + { + *out << "strerror(ENOENT) = " << result << endl; + } + + // Path conversion: from cygwin to Windows... + result = cygwin.win_path ("/usr"); + struct _stat statbuf; + if (::_stat (result.c_str (), &statbuf) < 0) + { + cerr << "stat(\"" << result << "\") failed!" << endl; + return 2; + } + else if (verbose) + { + *out << "/usr == " << result << endl; + } + + // ...and back: + char buf[MAX_PATH], scratch[256]; + GetSystemDirectory (buf, sizeof(buf)); + int (*cygstat) (const char *, void *); + cygwin.get_symbol ("stat", cygstat); + + if (cygstat (buf, scratch) < 0) + { + cerr << "cygwin stat(\"" << buf << "\") failed!" << endl; + return 3; + } + else if (verbose) + { + *out << buf << " == " << cygwin.unix_path(buf) << endl; + } + + // Test error handling. This should output + // "open(/potrzebie/furshlugginer): No such file or directory" + { + int (*cygopen) (const char *, int); + cygwin.get_symbol ("open", cygopen); + + if (cygopen ("/potrzebie/furshlugginer", 0 /* O_RDONLY */ ) < 0) + { + int err = cygwin.err_no (); + if (err != ENOENT) + { + cerr << "cygwin open(\"/potrzebie/furshlugginer\", " + "O_RDONLY): expected to fail with ENOENT, got " + << err << "!" << endl; + return 4; + } + if (verbose) + *out << cygwin::error (&cygwin, "open", + "/potrzebie/furshlugginer").what () + << endl; + } + else + { + cerr << "/potrzebie/furshlugginer should not exist!" + << endl; + return 5; + } + } + + // And signal handling: + std::pointer_to_unary_function < int , void > h1 (&hangup); + std::pointer_to_unary_function < int , void > h2 (&interrupt); + std::pointer_to_unary_function < int , void > h3 (&catch_signal); + cygwin.set_handler (SIGHUP, &h1); + cygwin.set_handler (SIGINT, &h2); + cygwin.set_handler (SIGUSR1, &h3); + + // Make sure the signal handler thread has had time to start... + Sleep (100); + // Send a test signal to set "caught" to true... + int (*raze) (int); + cygwin.get_symbol ("raise", raze); + raze (SIGUSR1); + // And give the thread time to wait for the shutdown signal. + Sleep (100); + + if (testinterrupts) + { + // This is a worst case scenario for testing interrupts: the + // main thread is in a long-duration Windows API call. This + // makes the main thread uninterruptible; cygwin will retry + // 20 times, with a low_priority_sleep(0) between each try. + cout << "Sleeping for 30 seconds, waiting for a signal..." << endl; + Sleep (30000); + cout << "Done waiting." << endl; + } + } + catch (std::exception &x) + { + cerr << x.what () << endl; + return 2; + } + + if (caught) + return 0; + else + { + cerr << "Never received SIGUSR1." << endl; + return 1; + } +} diff --git a/winsup/testsuite/winsup.api/cygload.exp b/winsup/testsuite/winsup.api/cygload.exp new file mode 100644 index 000000000..a07a549f9 --- /dev/null +++ b/winsup/testsuite/winsup.api/cygload.exp @@ -0,0 +1,40 @@ +source "site.exp" + +if { ! [isnative] } { + verbose "skipping cygload because it's not native \"$target_triplet\" != \"$build_triplet\"" + return +} + +proc ws_spawn {cmd args} { + global rv + verbose "running $cmd\n" + set rv {} + # First item in rv is the return code, second item is the message + lappend rv [catch "exec $cmd" message] $message + verbose send "catchCode = $rv\n" +} + +ws_spawn "gcc -mno-cygwin $srcdir/$subdir/cygload.cc -o mingw-cygload.exe -lstdc++ -Wl,-e,_cygloadCRTStartup@0" + +if { $rv != {0 {}} } { + verbose -log "$rv" + fail "cygload (compile)" +} else { + if { $verbose } { + set redirect_output "./mingw-cygwin.log" + } else { + set redirect_output /dev/null + } + set windows_runtime_root [exec cygpath -m $runtime_root] + ws_spawn "./mingw-cygload.exe -cygwin $windows_runtime_root/cygwin0.dll > $redirect_output" + if { $rv != {0 {}} } { + verbose -log "cygload: $rv" + fail "cygload (execute)" + } else { + pass "cygload" + } + catch { file delete "mingw-cygload.exe" } err + if { $err != "" } { + note "error deleting mingw-cygload.exe: $err" + } +} diff --git a/winsup/testsuite/winsup.api/cygload.h b/winsup/testsuite/winsup.api/cygload.h new file mode 100644 index 000000000..226a3f8da --- /dev/null +++ b/winsup/testsuite/winsup.api/cygload.h @@ -0,0 +1,158 @@ +// cygload.h -*- C++ -*- +// +// Copyright 2005, Red Hat, Inc. +// +// Written by Max Kaehn +// +// This software is a copyrighted work licensed under the terms of the +// Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. +// +// Note that dynamically linking to cygwin1.dll automatically places your code +// under the GPL unless you purchase a Cygwin Contract with Red Hat, Inc. +// See http://www.redhat.com/software/cygwin/ for more information. + +// This program has large numbers of progress messages so as to provide +// maximum information about crash locations for anyone without access to +// a Microsoft debugger. + + +// This file contains the basic infrastructure for connecting an MSVC +// process to Cygwin. + +#ifndef __CYGLOAD_H__ +#define __CYGLOAD_H__ + +#include // for GetProcAddress() +#include // for pointer_to_unary_function +#include // for runtime_error +#include +#include +#include + +// Convert GetLastError() to a human-readable STL exception. +class windows_error : public std::runtime_error +{ +public: + windows_error (const char *message, const char *detail = NULL) + : runtime_error (format (GetLastError (), message, detail)) { } + windows_error(DWORD error, const char *message, const char *detail = NULL) + : runtime_error (format (error, message, detail)) { } + + static std::string format (DWORD error, const char *message, + const char *detail); +}; + +namespace cygwin +{ + + // Cygwin keeps important thread-local information at the top of the + // stack. Its DllMain-equivalent will do the right thing for any threads + // you spawn, but you need to declare one of these as the very first thing + // in your main() function so horrible things won't happen when cygwin + // overwrites your stack. This will back up the data that will be + // overwritten and restore it when the destructor is called. + class padding { + public: + padding (); + ~padding (); + + // Verifies that padding has been declared. + static void check (); + + private: + std::vector< char > _backup; + char *_stackbase, *_end; + + // gdb reports sizeof(_cygtls) == 3964 at the time of this writing. + // This is at the end of the object so it'll be toward the bottom + // of the stack when it gets declared. + char _padding[8192]; + + static padding *_main; + static DWORD _mainTID; + }; + + // This hooks your application up to cygwin: it loads cygwin1.dll, + // initializes it properly, grabs some important symbols, and + // spawns a thread to let you receive signals from cygwin. + class connector { + public: + connector (const char *dll = "cygwin1.dll"); + ~connector (); + + // A wrapper around GetProcAddress() for fetching symbols from the + // cygwin DLL. Can throw windows_error. + template < class T > void get_symbol (const char *name, T &fn) const; + + // Wrappers for errno() and strerror(). + int err_no () const; + std::string str_error (int) const; + + // Converting between the worlds of Windows and Cygwin. + std::string unix_path (const std::string &windows) const; + std::string win_path (const std::string &unix) const; + + private: + HMODULE _library; + + int *(*_errno) (); + const char *(*_strerror) (int); + void (*_conv_to_full_posix_path) (const char *, char *); + void (*_conv_to_full_win32_path) (const char *, char *); + + public: + // The constructor will automatically hook you up for receiving + // cygwin signals. Just specify a signal and pass in a signal_handler. + typedef std::pointer_to_unary_function signal_handler; + signal_handler *set_handler (int signal, signal_handler *); + + private: + // Cygwin signals can only be received in threads that are calling + // interruptible functions or otherwise ready to intercept signals, so + // we spawn a thread that does nothing but call sigwait(). + + // This is the entry point: + static DWORD WINAPI signal_thread (void *); + // It runs this: + void await_signal (); + // And will execute this on receipt of any signal for which it's + // registered: + void handle_signals (int); + + HANDLE _signal_thread; + bool _waiting_for_signals, _signal_thread_done; + CRITICAL_SECTION _thread_mutex; + + typedef std::map< int, signal_handler * > callback_list; + callback_list _signal_handlers; + }; + + template void connector::get_symbol (const char *name, + T &symbol) const + { + FARPROC retval = NULL; + + retval = GetProcAddress (_library, name); + + if (retval == NULL) + throw windows_error ("GetProcAddress", name); + + symbol = reinterpret_cast < T > (retval); + } + + // cygwin::error converts errno to a human-readable exception. + class error : public std::runtime_error + { + public: + error (connector *c, const char *function, const char *detail = NULL) + : runtime_error (format (c, c->err_no (), function, detail)) { } + error (connector *c, int err_no, const char *function, + const char *detail = NULL) + : runtime_error (format (c, err_no, function, detail)) { } + + static std::string format(connector *c, int err_no, + const char *message, const char *detail); + }; +} + +#endif // __CYGLOAD_H__ diff --git a/winsup/testsuite/winsup.api/resethand.c b/winsup/testsuite/winsup.api/resethand.c index 2d1ccabc9..7d58dcd2c 100644 --- a/winsup/testsuite/winsup.api/resethand.c +++ b/winsup/testsuite/winsup.api/resethand.c @@ -8,7 +8,6 @@ int doit = 0; void ouch (int sig) { - fprintf (stderr, "ouch %d\n", sig); if (doit++ > 0) kill (getpid (), SIGTERM); } @@ -32,6 +31,6 @@ main (int argc, char **argv) exit (0x42); } status &= ~0x80; // remove core dump flag - fprintf (stderr, "pid %d exited with status %p\n", pid, (void *) status); + printf ("pid %d exited with status %p\n", pid, (void *) status); exit (argc == 1 ? !(status == SIGSEGV) : !(status == SIGTERM)); } diff --git a/winsup/testsuite/winsup.api/winsup.exp b/winsup/testsuite/winsup.api/winsup.exp index 26d3af0d2..639096267 100644 --- a/winsup/testsuite/winsup.api/winsup.exp +++ b/winsup/testsuite/winsup.api/winsup.exp @@ -29,7 +29,7 @@ proc ws_spawn {cmd args} { verbose "Filter: $test_filter" -foreach src [glob -nocomplain $srcdir/$subdir/*.c $srcdir/$subdir/*/*.c] { +foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/$subdir/*/*.{cc,c}]] { if { $test_filter != "" && ! [regexp $test_filter $src] } { verbose -log "Skipping $src" continue @@ -48,32 +48,36 @@ foreach src [glob -nocomplain $srcdir/$subdir/*.c $srcdir/$subdir/*/*.c] { clear_xfail } - ws_spawn "$CC -nodefaultlibs -mwin32 $CFLAGS $src $add_includes $add_libs $runtime_root/binmode.o -lgcc $runtime_root/libcygwin0.a -lkernel32 -luser32 -o $base.exe" - if { $rv != "" } { - verbose -log "$rv" - fail "$testcase (compile)" + if [ file exists "$srcdir/$subdir/$basename.exp" ] then { + source "$srcdir/$subdir/$basename.exp" } else { - if { $verbose } { - set redirect_output "./$base.log" - } else { - set redirect_output /dev/null - } - ws_spawn "$rootme/cygrun ./$base.exe > $redirect_output" - if { $rv != "" } { - verbose -log "$testcase: $rv" - fail "$testcase (execute)" - if { $xfail_expected } { - catch { file delete "$base.exe" } err - if { $err != "" } { - note "error deleting $base.exe: $err" - } - } + ws_spawn "$CC -nodefaultlibs -mwin32 $CFLAGS $src $add_includes $add_libs $runtime_root/binmode.o -lgcc $runtime_root/libcygwin0.a -lkernel32 -luser32 -o $base.exe" + if { $rv != "" } { + verbose -log "$rv" + fail "$testcase (compile)" } else { - pass "$testcase" - if { ! $xfail_expected } { - catch { file delete "$base.exe" } err - if { $err != "" } { - note "error deleting $base.exe: $err" + if { $verbose } { + set redirect_output "./$base.log" + } else { + set redirect_output /dev/null + } + ws_spawn "$rootme/cygrun ./$base.exe > $redirect_output" + if { $rv != "" } { + verbose -log "$testcase: $rv" + fail "$testcase (execute)" + if { $xfail_expected } { + catch { file delete "$base.exe" } err + if { $err != "" } { + note "error deleting $base.exe: $err" + } + } + } else { + pass "$testcase" + if { ! $xfail_expected } { + catch { file delete "$base.exe" } err + if { $err != "" } { + note "error deleting $base.exe: $err" + } } } } -- cgit v1.2.3