blob: 7326a9c0e28318f83f7ff66aa5c62cb3ae8a26a7 [file] [log] [blame]
Ben Craigb2501a72013-09-13 12:29:43 -05001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#ifndef _THRIFT_WINDOWS_OverlappedSubmissionThread_H_
21#define _THRIFT_WINDOWS_OverlappedSubmissionThread_H_ 1
22
23#ifndef _WIN32
24#error "OverlappedSubmissionThread.h is only usable on Windows"
25#endif
26
27#include <thrift/windows/Sync.h>
Mario Emmenlauerd270b352020-11-19 09:43:34 +010028#include <thrift/TNonCopyable.h>
Ben Craigb2501a72013-09-13 12:29:43 -050029
30/*
31 *** Why does this class exist?
32 In short, because we want to enable something similar to a "select" loop, on Windows, with
33 named pipes. The core of the "select" loop is a call to WaitForMultipleObjects. So that means
34 we need a signalable object that indicates when data is available.
35
36 A pipe handle doesn't do that. A pipe handle is signaled when a read or write completes, and if
37 no one has called read or write, then the pipe handle is useless in WaitForMultipleObjects. So
38 instead, we use overlapped I/O. With overlapped I/O, you call read, and associate an event with
39 the read. When the read finishes, the event is signaled. This means that when you create a pipe,
40 you start a read. When the customer calls read on your transport object, you wait for the last
41 read to finish, and then kick off another.
42
43 There is one big caveat to this though. The thread that initiated the read must stay alive. If
44 the thread that initiated the read exits, then the read completes in an error state. To ensure
45 that the initiating thread stays alive, we create a singleton thread whose sole responsibility is
46 to manage this overlapped I/O requests. This introduces some overhead, but it is overhead that
47 is necessary for correct behavior.
48
49 This thread currently supports connect, read, and cancel io. So far, I haven't needed to put any
50 writes on this thread, but if needed, it could be done. The client write buffer would need to be
51 copied to ensure that it doesn't get invalidated.
52
53 *** How does one use this class?
54 Create a TOverlappedWorkItem, and fill in the action and "h", then call reset(). Your work item
55 is now ready to be submitted to the overlapped submission thread. Create a TAutoOverlapThread,
56 and call thread->addWorkItem with your work item. After addWorkItem completes, you may inspect
57 last_error and success. At some point in the future, call workItem.overlappedResults to wait
58 until the operation has completed.
59*/
60
Konrad Grochowski16a23a62014-11-13 15:33:38 +010061namespace apache {
62namespace thrift {
63namespace transport {
Ben Craigb2501a72013-09-13 12:29:43 -050064
James E. King, IIIbff04462017-02-11 01:18:03 -050065struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) TOverlappedWorkItem : public SLIST_ENTRY {
Ben Craigb2501a72013-09-13 12:29:43 -050066 TOverlappedWorkItem();
67
68 enum action_t {
Konrad Grochowski16a23a62014-11-13 15:33:38 +010069 UNKNOWN = 3000,
Ben Craigb2501a72013-09-13 12:29:43 -050070 CONNECT,
71 READ,
72 CANCELIO,
73 STOP,
74 };
75
76 TAutoResetEvent doneSubmittingEvent;
77 action_t action;
78 HANDLE h;
Konrad Grochowski16a23a62014-11-13 15:33:38 +010079 uint8_t* buffer;
Ben Craigb2501a72013-09-13 12:29:43 -050080 uint32_t buffer_len;
81 OVERLAPPED overlap;
82
83 DWORD last_error;
84 BOOL success;
85
Konrad Grochowski16a23a62014-11-13 15:33:38 +010086 void reset(uint8_t* buf, uint32_t len, HANDLE event);
Ben Craigb2501a72013-09-13 12:29:43 -050087 uint32_t overlappedResults(bool signal_failure = true);
88 bool process();
89};
90
Mario Emmenlauerd270b352020-11-19 09:43:34 +010091class TOverlappedSubmissionThread : apache::thrift::TNonCopyable {
Ben Craigb2501a72013-09-13 12:29:43 -050092public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010093 void addWorkItem(TOverlappedWorkItem* item);
Ben Craigb2501a72013-09-13 12:29:43 -050094
Konrad Grochowski16a23a62014-11-13 15:33:38 +010095 // singleton stuff
Ben Craigb2501a72013-09-13 12:29:43 -050096public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010097 static TOverlappedSubmissionThread* acquire_instance();
Ben Craigb2501a72013-09-13 12:29:43 -050098 static void release_instance();
Konrad Grochowski16a23a62014-11-13 15:33:38 +010099
Ben Craigb2501a72013-09-13 12:29:43 -0500100private:
101 static TCriticalSection instanceGuard_;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100102 static TOverlappedSubmissionThread* instance_;
Ben Craigb2501a72013-09-13 12:29:43 -0500103 static uint32_t instanceRefCount_;
104
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100105 // thread details
Ben Craigb2501a72013-09-13 12:29:43 -0500106private:
107 TOverlappedSubmissionThread();
Chris Friedtdb371252023-01-20 15:12:25 -0500108 virtual ~TOverlappedSubmissionThread();
Ben Craigb2501a72013-09-13 12:29:43 -0500109 void run();
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100110 static unsigned __stdcall thread_proc(void* addr);
Ben Craigb2501a72013-09-13 12:29:43 -0500111
112private:
113 DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) SLIST_HEADER workList_;
114 TOverlappedWorkItem stopItem_;
115 TAutoResetEvent workAvailableEvent_;
116 HANDLE thread_;
117};
118
Mario Emmenlauerd270b352020-11-19 09:43:34 +0100119class TAutoOverlapThread : apache::thrift::TNonCopyable {
Ben Craigb2501a72013-09-13 12:29:43 -0500120private:
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100121 TOverlappedSubmissionThread* p;
122
Ben Craigb2501a72013-09-13 12:29:43 -0500123public:
124 TAutoOverlapThread() : p(TOverlappedSubmissionThread::acquire_instance()) {}
Chris Friedtdb371252023-01-20 15:12:25 -0500125 virtual ~TAutoOverlapThread() { TOverlappedSubmissionThread::release_instance(); }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100126 TOverlappedSubmissionThread* operator->() { return p; }
Ben Craigb2501a72013-09-13 12:29:43 -0500127};
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100128}
129}
130} // apache::thrift::transport
Ben Craigb2501a72013-09-13 12:29:43 -0500131
132#endif