E-MailRelay

gfutureevent_win32.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gfutureevent_win32.cpp
19///
20
21#include "gdef.h"
22#include "gfutureevent.h"
23#include "geventloop.h"
24#include "gstr.h"
25#include "glog.h"
26
27#if ! GCONFIG_HAVE_WINDOWS_CREATE_EVENT_EX
28HANDLE CreateEventEx( LPSECURITY_ATTRIBUTES sec , LPCTSTR name , DWORD flags , DWORD )
29{
30 BOOL manual_reset = ( flags & 1 ) ? TRUE : FALSE ;
31 BOOL initial_state = ( flags & 2 ) ? TRUE : FALSE ;
32 return CreateEvent( sec , manual_reset , initial_state , name ) ;
33}
34#endif
35
36#ifndef CREATE_EVENT_MANUAL_RESET
37#define CREATE_EVENT_MANUAL_RESET 1
38#endif
39
40 class GNet::FutureEventImp : public EventHandler
41{
42 public:
43 FutureEventImp( FutureEventHandler & handler , EventState es ) ;
44 // Constructor.
45
46 ~FutureEventImp() override ;
47 // Destructor.
48
49 static bool send( HANDLE , bool ) noexcept ;
50 // Raises an event.
51
52 HANDLE handle() noexcept ;
53 // Extracts the event-object handle.
54
55private: // overrides
56 void readEvent() override ; // GNet::EventHandler
57
58public:
59 FutureEventImp( const FutureEventImp & ) = delete ;
60 FutureEventImp( FutureEventImp && ) = delete ;
61 FutureEventImp & operator=( const FutureEventImp & ) = delete ;
62 FutureEventImp & operator=( FutureEventImp && ) = delete ;
63
64private:
65 HANDLE dup() ;
66
67private:
68 struct Handle
69 {
70 Handle() = default ;
71 ~Handle() { if(h) CloseHandle(h) ; }
72 Handle & operator=( HANDLE h_ ) { h = h_ ; return *this ; }
73 bool operator==( HANDLE h_ ) const { return h == h_ ; }
74 Handle( const Handle & ) = delete ;
75 Handle( Handle && ) = delete ;
76 Handle & operator=( const Handle & ) = delete ;
77 Handle & operator=( Handle && ) = delete ;
78 HANDLE h{0} ;
79 } ;
80
81 private:
82 FutureEventHandler & m_handler ;
83 EventState m_es ;
84 Handle m_h ;
85 Handle m_h2 ;
86} ;
87
88GNet::FutureEventImp::FutureEventImp( FutureEventHandler & handler , EventState es ) :
89 m_handler(handler) ,
90 m_es(es)
91{
92 m_h = FutureEvent::createHandle() ;
93 if( m_h == 0 )
94 throw FutureEvent::Error( "CreateEventEx" ) ;
95
96 m_h2 = dup() ;
97
98 EventLoop::instance().addRead( Descriptor(INVALID_SOCKET,m_h.h) , *this , es ) ;
99}
100
101GNet::FutureEventImp::~FutureEventImp()
102{
103 if( EventLoop::exists() )
104 EventLoop::instance().dropRead( Descriptor(INVALID_SOCKET,m_h.h) ) ;
105}
106
107HANDLE GNet::FutureEventImp::dup()
108{
109 // duplicate the handle so that the kernel object is only deleted
110 // once both handles are closed -- we need the main thread and the
111 // worker thread to both keep the kernel event-object alive
112 HANDLE h = 0 ;
113 BOOL ok = DuplicateHandle(
114 GetCurrentProcess() , m_h.h ,
115 GetCurrentProcess() , &h ,
116 0 , FALSE , DUPLICATE_SAME_ACCESS ) ;
117 if( !ok )
118 {
119 DWORD e = GetLastError() ;
120 throw FutureEvent::Error( "DuplicateHandle" , G::Str::fromUInt(static_cast<unsigned int>(e)) ) ;
121 }
122 return h ;
123}
124
125HANDLE GNet::FutureEventImp::handle() noexcept
126{
127 HANDLE h2 = 0 ;
128 std::swap( h2 , m_h2.h ) ;
129 return h2 ;
130}
131
132 bool GNet::FutureEventImp::send( HANDLE handle , bool close ) noexcept
133{
134 bool ok = SetEvent( handle ) != 0 ;
135 if( close )
136 CloseHandle( handle ) ; // kernel event-object still open
137 return ok ;
138}
139
140 void GNet::FutureEventImp::readEvent()
141{
142 G_DEBUG( "GNet::FutureEventImp::readEvent: future event: h=" << m_h.h ) ;
143 m_handler.onFutureEvent() ;
144}
145
146// ==
147
148 GNet::FutureEvent::FutureEvent( FutureEventHandler & handler , EventState es ) :
149 m_imp(std::make_unique<FutureEventImp>(handler,es))
150{
151}
152
153 GNet::FutureEvent::~FutureEvent()
154= default ;
155
156 bool GNet::FutureEvent::send( HANDLE handle , bool close ) noexcept
157{
158 return FutureEventImp::send( handle , close ) ;
159}
160
161HANDLE GNet::FutureEvent::handle() noexcept
162{
163 return m_imp->handle() ;
164}
165
166HANDLE GNet::FutureEvent::createHandle()
167{
168 const DWORD access = DELETE | SYNCHRONIZE | EVENT_MODIFY_STATE | PROCESS_DUP_HANDLE ;
169 return CreateEventEx( nullptr , nullptr , CREATE_EVENT_MANUAL_RESET , access ) ;
170}
171
GNet::EventHandler::readEvent
virtual void readEvent()
Called for a read event.
Definition: geventhandler.cpp:39
GNet::FutureEvent::FutureEvent
FutureEvent(FutureEventHandler &, EventState)
Constructor. Installs itself in the event loop.
Definition: gfutureevent_unix.cpp:150
GNet::FutureEvent::send
static bool send(HANDLE handle, bool close=true) noexcept
Pokes an event into the main event loop so that the FutureEventHandler callback is called asynchronou...
Definition: gfutureevent_unix.cpp:158
GNet::FutureEvent::handle
HANDLE handle() noexcept
Extracts a handle that can be passed between threads and used in send().
Definition: gfutureevent_unix.cpp:163
GNet::FutureEvent::createHandle
static HANDLE createHandle()
Used by some event loop implementations to create the underlying synchronisation object.
Definition: gfutureevent_win32.cpp:166
GNet::FutureEvent::~FutureEvent
~FutureEvent()
Destructor.
G::Str::fromUInt
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
Definition: gstr.h:612
geventloop.h
gfutureevent.h
glog.h
gstr.h
std
STL namespace.