Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-17 08:35:04

0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one
0003  * or more contributor license agreements. See the NOTICE file
0004  * distributed with this work for additional information
0005  * regarding copyright ownership. The ASF licenses this file
0006  * to you under the Apache License, Version 2.0 (the
0007  * "License"); you may not use this file except in compliance
0008  * with the License. You may obtain a copy of the License at
0009  *
0010  *   http://www.apache.org/licenses/LICENSE-2.0
0011  *
0012  * Unless required by applicable law or agreed to in writing,
0013  * software distributed under the License is distributed on an
0014  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015  * KIND, either express or implied. See the License for the
0016  * specific language governing permissions and limitations
0017  * under the License.
0018  */
0019 
0020 #ifndef _THRIFT_WINDOWS_OverlappedSubmissionThread_H_
0021 #define _THRIFT_WINDOWS_OverlappedSubmissionThread_H_ 1
0022 
0023 #ifndef _WIN32
0024 #error "OverlappedSubmissionThread.h is only usable on Windows"
0025 #endif
0026 
0027 #include <thrift/windows/Sync.h>
0028 #include <thrift/TNonCopyable.h>
0029 
0030 /*
0031   *** Why does this class exist?
0032   In short, because we want to enable something similar to a "select" loop, on Windows, with
0033   named pipes.  The core of the "select" loop is a call to WaitForMultipleObjects.  So that means
0034   we need a signalable object that indicates when data is available.
0035 
0036   A pipe handle doesn't do that.  A pipe handle is signaled when a read or write completes, and if
0037   no one has called read or write, then the pipe handle is useless in WaitForMultipleObjects.  So
0038   instead, we use overlapped I/O.  With overlapped I/O, you call read, and associate an event with
0039   the read.  When the read finishes, the event is signaled.  This means that when you create a pipe,
0040   you start a read.  When the customer calls read on your transport object, you wait for the last
0041   read to finish, and then kick off another.
0042 
0043   There is one big caveat to this though.  The thread that initiated the read must stay alive.  If
0044   the thread that initiated the read exits, then the read completes in an error state.  To ensure
0045   that the initiating thread stays alive, we create a singleton thread whose sole responsibility is
0046   to manage this overlapped I/O requests.  This introduces some overhead, but it is overhead that
0047   is necessary for correct behavior.
0048 
0049   This thread currently supports connect, read, and cancel io.  So far, I haven't needed to put any
0050   writes on this thread, but if needed, it could be done.  The client write buffer would need to be
0051   copied to ensure that it doesn't get invalidated.
0052 
0053   *** How does one use this class?
0054   Create a TOverlappedWorkItem, and fill in the action and "h", then call reset().  Your work item
0055   is now ready to be submitted to the overlapped submission thread.  Create a TAutoOverlapThread,
0056   and call thread->addWorkItem with your work item.  After addWorkItem completes, you may inspect
0057   last_error and success.  At some point in the future, call workItem.overlappedResults to wait
0058   until the operation has completed.
0059 */
0060 
0061 namespace apache {
0062 namespace thrift {
0063 namespace transport {
0064 
0065 struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) TOverlappedWorkItem : public SLIST_ENTRY {
0066   TOverlappedWorkItem();
0067 
0068   enum action_t {
0069     UNKNOWN = 3000,
0070     CONNECT,
0071     READ,
0072     CANCELIO,
0073     STOP,
0074   };
0075 
0076   TAutoResetEvent doneSubmittingEvent;
0077   action_t action;
0078   HANDLE h;
0079   uint8_t* buffer;
0080   uint32_t buffer_len;
0081   OVERLAPPED overlap;
0082 
0083   DWORD last_error;
0084   BOOL success;
0085 
0086   void reset(uint8_t* buf, uint32_t len, HANDLE event);
0087   uint32_t overlappedResults(bool signal_failure = true);
0088   bool process();
0089 };
0090 
0091 class TOverlappedSubmissionThread : apache::thrift::TNonCopyable {
0092 public:
0093   void addWorkItem(TOverlappedWorkItem* item);
0094 
0095   // singleton stuff
0096 public:
0097   static TOverlappedSubmissionThread* acquire_instance();
0098   static void release_instance();
0099 
0100 private:
0101   static TCriticalSection instanceGuard_;
0102   static TOverlappedSubmissionThread* instance_;
0103   static uint32_t instanceRefCount_;
0104 
0105   // thread details
0106 private:
0107   TOverlappedSubmissionThread();
0108   virtual ~TOverlappedSubmissionThread();
0109   void run();
0110   static unsigned __stdcall thread_proc(void* addr);
0111 
0112 private:
0113   DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) SLIST_HEADER workList_;
0114   TOverlappedWorkItem stopItem_;
0115   TAutoResetEvent workAvailableEvent_;
0116   HANDLE thread_;
0117 };
0118 
0119 class TAutoOverlapThread : apache::thrift::TNonCopyable {
0120 private:
0121   TOverlappedSubmissionThread* p;
0122 
0123 public:
0124   TAutoOverlapThread() : p(TOverlappedSubmissionThread::acquire_instance()) {}
0125   virtual ~TAutoOverlapThread() { TOverlappedSubmissionThread::release_instance(); }
0126   TOverlappedSubmissionThread* operator->() { return p; }
0127 };
0128 }
0129 }
0130 } // apache::thrift::transport
0131 
0132 #endif