diff options
Diffstat (limited to 'winsup/testsuite/winsup.api/cygload.h')
-rw-r--r-- | winsup/testsuite/winsup.api/cygload.h | 158 |
1 files changed, 158 insertions, 0 deletions
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 <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[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<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__ |