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

[Patch] Testing loads of cygwin1.dll from MinGW and MSVC, take 3


This patch contains a revised version of the "cygload" test utility,
this time with even better adherence to cygwin naming and indentation.
Igor, thanks for pointing me at "indent"-- it also pointed out
that I was forgetting to put spaces in front of the parameter
lists for my function calls.

I'm using diff -upN against an empty directory "winsup/testsuite/cyglode";
I hope that's OK.
---
ChangeLog for winsup/testsuite:

2005-05-27  Max Kaehn <slothman@electric-cloud.com>

	* Makefile.in:  now tests cygload.
	* cygload:  New directory.
	* cygload/README:  New file.
	* cygload/Makefile:  Ditto.
	* cygload/cygload.h:  Ditto.
	* cygload/cygload.cc:  Ditto.
	* cygload/cygload.exp:  Ditto.
---
Index: winsup/testsuite/Makefile.in
===================================================================
RCS file: /cvs/src/src/winsup/testsuite/Makefile.in,v
retrieving revision 1.19
diff -u -p -r1.19 Makefile.in
--- winsup/testsuite/Makefile.in	6 Jul 2003 21:45:21 -0000	1.19
+++ winsup/testsuite/Makefile.in	6 Jun 2005 20:49:21 -0000
@@ -186,7 +186,8 @@ check: $(TESTSUP_LIB_NAME) $(RUNTIME) cy
 	   TCL_LIBRARY=`cd .. ; cd ${srcdir}/../../tcl/library ; pwd` ; \
 	    export TCL_LIBRARY ; fi ; \
 	PATH=$(bupdir)/cygwin:$${PATH} ;\
-	$(RUNTEST) --tool winsup $(RUNTESTFLAGS)
+	$(RUNTEST) --tool winsup $(RUNTESTFLAGS) ;\
+	$(RUNTEST) --tool cygload $(RUNTESTFLAGS)
 
 cygrun.o: cygrun.c
 	$(CC) $(MINGW_CFLAGS) -o $@ -c $<
diff -upN winsup/testsuite/cyglode/Makefile winsup/testsuite/cygload/Makefile
--- winsup/testsuite/cyglode/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ winsup/testsuite/cygload/Makefile	2005-06-06 13:18:01.000000000 -0700
@@ -0,0 +1,36 @@
+# 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 -upN winsup/testsuite/cyglode/README winsup/testsuite/cygload/README
--- winsup/testsuite/cyglode/README	1969-12-31 16:00:00.000000000 -0800
+++ winsup/testsuite/cygload/README	2005-05-27 14:31:06.000000000 -0700
@@ -0,0 +1,18 @@
+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 -upN winsup/testsuite/cyglode/cygload.cc winsup/testsuite/cygload/cygload.cc
--- winsup/testsuite/cyglode/cygload.cc	1969-12-31 16:00:00.000000000 -0800
+++ winsup/testsuite/cygload/cygload.cc	2005-06-06 13:54:31.000000000 -0700
@@ -0,0 +1,618 @@
+// cygload.cpp
+//
+// Copyright 2005, Red Hat, Inc.
+//
+// Written by Max Kaehn <slothman@electric-cloud.com>
+//
+// 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 <iostream>
+#include <sstream>
+#include <vector>
+#include <errno.h>              // for ENOENT
+#include <sys/types.h>
+#include <sys/stat.h>
+
+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<void *>(_main->_stackbase)
+         << ".  padding ends at " << static_cast<void *>(_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 -upN winsup/testsuite/cyglode/cygload.exp winsup/testsuite/cygload/cygload.exp
--- winsup/testsuite/cyglode/cygload.exp	1969-12-31 16:00:00.000000000 -0800
+++ winsup/testsuite/cygload/cygload.exp	2005-06-06 11:44:13.000000000 -0700
@@ -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.cpp -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 -upN winsup/testsuite/cyglode/cygload.h winsup/testsuite/cygload/cygload.h
--- winsup/testsuite/cyglode/cygload.h	1969-12-31 16:00:00.000000000 -0800
+++ winsup/testsuite/cygload/cygload.h	2005-06-06 13:54:27.000000000 -0700
@@ -0,0 +1,155 @@
+// cygload.h                                      -*- C++ -*-
+//
+// Copyright 2005, Red Hat, Inc.
+//
+// Written by Max Kaehn <slothman@electric-cloud.com>
+//
+// 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 <windows.h>            // for GetProcAddress()
+#include <functional>           // for pointer_to_unary_function
+#include <stdexcept>            // for runtime_error
+#include <string>
+#include <map>
+#include <vector>
+
+// 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<int,void> 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 <class T> 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__



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