summaryrefslogtreecommitdiff
path: root/wait.h
blob: 924ed42b94741b348aee217effcde71769595c5a (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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// wait.h - originally written and placed in the public domain by Wei Dai

#ifndef CRYPTOPP_WAIT_H
#define CRYPTOPP_WAIT_H

#include "config.h"

#if !defined(NO_OS_DEPENDENCE) && (defined(SOCKETS_AVAILABLE) || defined(WINDOWS_PIPES_AVAILABLE))

#include "cryptlib.h"
#include "misc.h"
#include "stdcpp.h"

#ifdef USE_WINDOWS_STYLE_SOCKETS
#include <winsock2.h>
#else
#include <sys/types.h>
#include <sys/select.h>
#endif

// For definitions of VOID, PVOID, HANDLE, PHANDLE, etc.
#if defined(CRYPTOPP_WIN32_AVAILABLE)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#include "hrtimer.h"

#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
#  define CRYPTOPP_MSAN 1
# endif
#endif

// http://connect.microsoft.com/VisualStudio/feedback/details/1581706
//   and http://github.com/weidai11/cryptopp/issues/214
#if (CRYPTOPP_MSC_VERSION >= 1900)
# pragma warning(push)
# pragma warning(disable: 4589)
#endif

NAMESPACE_BEGIN(CryptoPP)

class Tracer
{
public:
	Tracer(unsigned int level) : m_level(level) {}
	virtual ~Tracer() {}

protected:
	/// Override this in your most-derived tracer to do the actual tracing.
	virtual void Trace(unsigned int n, std::string const& s) = 0;

	/*! By default, tracers will decide which trace messages to trace according to a trace level
		mechanism. If your most-derived tracer uses a different mechanism, override this to
		return false. If this method returns false, the default TraceXxxx(void) methods will all
		return 0 and must be overridden explicitly by your tracer for trace messages you want. */
	virtual bool UsingDefaults() const { return true; }

protected:
	unsigned int m_level;

	void TraceIf(unsigned int n, std::string const&s)
		{ if (n) Trace(n, s); }

	/*! Returns nr if, according to the default log settings mechanism (using log levels),
	    the message should be traced. Returns 0 if the default trace level mechanism is not
		in use, or if it is in use but the event should not be traced. Provided as a utility
		method for easier and shorter coding of default TraceXxxx(void) implementations. */
	unsigned int Tracing(unsigned int nr, unsigned int minLevel) const
		{ return (UsingDefaults() && m_level >= minLevel) ? nr : 0; }
};

// Your Tracer-derived class should inherit as virtual public from Tracer or another
// Tracer-derived class, and should pass the log level in its constructor. You can use the
// following methods to begin and end your Tracer definition.

// This constructor macro initializes Tracer directly even if not derived directly from it;
// this is intended, virtual base classes are always initialized by the most derived class.
#define CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED) \
	public: DERIVED(unsigned int level = 0) : Tracer(level) {}

#define CRYPTOPP_BEGIN_TRACER_CLASS_1(DERIVED, BASE1) \
	class DERIVED : virtual public BASE1, public NotCopyable { CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED)

#define CRYPTOPP_BEGIN_TRACER_CLASS_2(DERIVED, BASE1, BASE2) \
	class DERIVED : virtual public BASE1, virtual public BASE2, public NotCopyable { CRYPTOPP_TRACER_CONSTRUCTOR(DERIVED)

#define CRYPTOPP_END_TRACER_CLASS };

// In your Tracer-derived class, you should define a globally unique event number for each
// new event defined. This can be done using the following macros.

#define CRYPTOPP_BEGIN_TRACER_EVENTS(UNIQUENR)	enum { EVENTBASE = UNIQUENR,
#define CRYPTOPP_TRACER_EVENT(EVENTNAME)				EventNr_##EVENTNAME,
#define CRYPTOPP_END_TRACER_EVENTS				};

// In your own Tracer-derived class, you must define two methods per new trace event type:
// - unsigned int TraceXxxx() const
//   Your default implementation of this method should return the event number if according
//   to the default trace level system the event should be traced, or 0 if it should not.
// - void TraceXxxx(string const& s)
//   This method should call TraceIf(TraceXxxx(), s); to do the tracing.
// For your convenience, a macro to define these two types of methods are defined below.
// If you use this macro, you should also use the TRACER_EVENTS macros above to associate
// event names with numbers.

#define CRYPTOPP_TRACER_EVENT_METHODS(EVENTNAME, LOGLEVEL) \
	virtual unsigned int Trace##EVENTNAME() const { return Tracing(EventNr_##EVENTNAME, LOGLEVEL); } \
	virtual void Trace##EVENTNAME(std::string const& s) { TraceIf(Trace##EVENTNAME(), s); }


/*! A simple unidirectional linked list with m_prev == 0 to indicate the final entry.
    The aim of this implementation is to provide a very lightweight and practical
	tracing mechanism with a low performance impact. Functions and methods supporting
	this call-stack mechanism would take a parameter of the form "CallStack const& callStack",
	and would pass this parameter to subsequent functions they call using the construct:

	SubFunc(arg1, arg2, CallStack("my func at place such and such", &callStack));

	The advantage of this approach is that it is easy to use and should be very efficient,
	involving no allocation from the heap, just a linked list of stack objects containing
	pointers to static ASCIIZ strings (or possibly additional but simple data if derived). */
class CallStack
{
public:
	CallStack(char const* i, CallStack const* p) : m_info(i), m_prev(p) {}
	CallStack const* Prev() const { return m_prev; }
	virtual std::string Format() const;

protected:
	char const* m_info;
	CallStack const* m_prev;
};

/*! An extended CallStack entry type with an additional numeric parameter. */
class CallStackWithNr : public CallStack
{
public:
	CallStackWithNr(char const* i, word32 n, CallStack const* p) : CallStack(i, p), m_nr(n) {}
	std::string Format() const;

protected:
	word32 m_nr;
};

/*! An extended CallStack entry type with an additional string parameter. */
class CallStackWithStr : public CallStack
{
public:
	CallStackWithStr(char const* i, char const* z, CallStack const* p) : CallStack(i, p), m_z(z) {}
	std::string Format() const;

protected:
	char const* m_z;
};

// Thanks to Maximilian Zamorsky for help with http://connect.microsoft.com/VisualStudio/feedback/details/1570496/
CRYPTOPP_BEGIN_TRACER_CLASS_1(WaitObjectsTracer, Tracer)
	CRYPTOPP_BEGIN_TRACER_EVENTS(0x48752841)
		CRYPTOPP_TRACER_EVENT(NoWaitLoop)
	CRYPTOPP_END_TRACER_EVENTS
	CRYPTOPP_TRACER_EVENT_METHODS(NoWaitLoop, 1)
CRYPTOPP_END_TRACER_CLASS

struct WaitingThreadData;

/// container of wait objects
class WaitObjectContainer : public NotCopyable
{
public:
	/// exception thrown by WaitObjectContainer
	class Err : public Exception
	{
	public:
		Err(const std::string& s) : Exception(IO_ERROR, s) {}
	};

	static unsigned int MaxWaitObjects();

	WaitObjectContainer(WaitObjectsTracer* tracer = NULLPTR);

	void Clear();
	void SetNoWait(CallStack const& callStack);
	void ScheduleEvent(double milliseconds, CallStack const& callStack);
	// returns false if timed out
	bool Wait(unsigned long milliseconds);

#ifdef USE_WINDOWS_STYLE_SOCKETS
	virtual ~WaitObjectContainer();
	void AddHandle(HANDLE handle, CallStack const& callStack);
#else
	void AddReadFd(int fd, CallStack const& callStack);
	void AddWriteFd(int fd, CallStack const& callStack);
#endif

private:
	WaitObjectsTracer* m_tracer;

#ifdef USE_WINDOWS_STYLE_SOCKETS
	void CreateThreads(unsigned int count);
	std::vector<HANDLE> m_handles;
	std::vector<WaitingThreadData *> m_threads;
	HANDLE m_startWaiting;
	HANDLE m_stopWaiting;
#else
	fd_set m_readfds, m_writefds;
	int m_maxFd;
#endif
	double m_firstEventTime;
	Timer m_eventTimer;
	bool m_noWait;

#ifdef USE_WINDOWS_STYLE_SOCKETS
	typedef size_t LastResultType;
#else
	typedef int LastResultType;
#endif
	enum { LASTRESULT_NOWAIT = -1, LASTRESULT_SCHEDULED = -2, LASTRESULT_TIMEOUT = -3 };
	LastResultType m_lastResult;
	unsigned int m_sameResultCount;
	Timer m_noWaitTimer;
	void SetLastResult(LastResultType result);
	void DetectNoWait(LastResultType result, CallStack const& callStack);
};

NAMESPACE_END

#if (CRYPTOPP_MSC_VERSION >= 1900)
# pragma warning(pop)
#endif

#endif  // NO_OS_DEPENDENCE

#endif // CRYPTOPP_WAIT_H