summaryrefslogtreecommitdiffstats
path: root/winsup/testsuite/winsup.api/cygload.h
blob: c7c5620934ab092194feeae81e96fbb8da9aeb3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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[32768];

    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__