1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: sw=4 ts=4 et :
3 : */
4 : /* ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Plugin App.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Chris Jones <jones.chris.g@gmail.com>
21 : * Portions created by the Initial Developer are Copyright (C) 2009
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef ipc_glue_SyncChannel_h
41 : #define ipc_glue_SyncChannel_h 1
42 :
43 : #include "mozilla/ipc/AsyncChannel.h"
44 :
45 : namespace mozilla {
46 : namespace ipc {
47 : //-----------------------------------------------------------------------------
48 :
49 : class SyncChannel : public AsyncChannel
50 : {
51 : protected:
52 : typedef IPC::Message::msgid_t msgid_t;
53 :
54 : public:
55 : static const int32 kNoTimeout;
56 :
57 : class /*NS_INTERFACE_CLASS*/ SyncListener :
58 : public AsyncChannel::AsyncListener
59 2 : {
60 : public:
61 2 : virtual ~SyncListener() { }
62 :
63 : virtual void OnChannelClose() = 0;
64 : virtual void OnChannelError() = 0;
65 : virtual Result OnMessageReceived(const Message& aMessage) = 0;
66 : virtual void OnProcessingError(Result aError) = 0;
67 : virtual bool OnReplyTimeout() = 0;
68 : virtual Result OnMessageReceived(const Message& aMessage,
69 : Message*& aReply) = 0;
70 0 : virtual void OnChannelConnected(int32 peer_pid) {};
71 : };
72 :
73 : SyncChannel(SyncListener* aListener);
74 : virtual ~SyncChannel();
75 :
76 : NS_OVERRIDE
77 0 : virtual bool Send(Message* msg) {
78 0 : return AsyncChannel::Send(msg);
79 : }
80 :
81 : // Synchronously send |msg| (i.e., wait for |reply|)
82 : virtual bool Send(Message* msg, Message* reply);
83 :
84 : // Set channel timeout value. Since this is broken up into
85 : // two period, the minimum timeout value is 2ms.
86 0 : void SetReplyTimeoutMs(int32 aTimeoutMs) {
87 0 : AssertWorkerThread();
88 : mTimeoutMs = (aTimeoutMs <= 0) ? kNoTimeout :
89 : // timeouts are broken up into two periods
90 0 : (int32)ceil((double)aTimeoutMs/2.0);
91 0 : }
92 :
93 : static bool IsPumpingMessages() {
94 : return sIsPumpingMessages;
95 : }
96 : static void SetIsPumpingMessages(bool aIsPumping) {
97 : sIsPumpingMessages = aIsPumping;
98 : }
99 :
100 : #ifdef OS_WIN
101 : public:
102 : struct NS_STACK_CLASS SyncStackFrame
103 : {
104 : SyncStackFrame(SyncChannel* channel, bool rpc);
105 : ~SyncStackFrame();
106 :
107 : bool mRPC;
108 : bool mSpinNestedEvents;
109 : bool mListenerNotified;
110 : SyncChannel* mChannel;
111 :
112 : /* the previous stack frame for this channel */
113 : SyncStackFrame* mPrev;
114 :
115 : /* the previous stack frame on any channel */
116 : SyncStackFrame* mStaticPrev;
117 : };
118 : friend struct SyncChannel::SyncStackFrame;
119 :
120 : static bool IsSpinLoopActive() {
121 : for (SyncStackFrame* frame = sStaticTopFrame;
122 : frame;
123 : frame = frame->mPrev) {
124 : if (frame->mSpinNestedEvents)
125 : return true;
126 : }
127 : return false;
128 : }
129 :
130 : protected:
131 : /* the deepest sync stack frame for this channel */
132 : SyncStackFrame* mTopFrame;
133 :
134 : /* the deepest sync stack frame on any channel */
135 : static SyncStackFrame* sStaticTopFrame;
136 : #endif // OS_WIN
137 :
138 : protected:
139 : // Executed on the link thread
140 : // Override the AsyncChannel handler so we can dispatch sync messages
141 : NS_OVERRIDE virtual void OnMessageReceivedFromLink(const Message& msg);
142 : NS_OVERRIDE virtual void OnChannelErrorFromLink();
143 :
144 : // Executed on the worker thread
145 0 : bool ProcessingSyncMessage() const {
146 0 : return mProcessingSyncMessage;
147 : }
148 :
149 : void OnDispatchMessage(const Message& aMsg);
150 :
151 : //
152 : // Return true if the wait ended because a notification was
153 : // received. That is, true => event received.
154 : //
155 : // Return false if the time elapsed from when we started the
156 : // process of waiting until afterwards exceeded the currently
157 : // allotted timeout. That *DOES NOT* mean false => "no event" (==
158 : // timeout); there are many circumstances that could cause the
159 : // measured elapsed time to exceed the timeout EVEN WHEN we were
160 : // notified.
161 : //
162 : // So in sum: true is a meaningful return value; false isn't,
163 : // necessarily.
164 : //
165 : bool WaitForNotify();
166 :
167 : bool ShouldContinueFromTimeout();
168 :
169 : // Executed on the IO thread.
170 : void NotifyWorkerThread();
171 :
172 : // On both
173 0 : bool AwaitingSyncReply() const {
174 0 : mMonitor->AssertCurrentThreadOwns();
175 0 : return mPendingReply != 0;
176 : }
177 :
178 0 : int32 NextSeqno() {
179 0 : AssertWorkerThread();
180 0 : return mChild ? --mNextSeqno : ++mNextSeqno;
181 : }
182 :
183 : msgid_t mPendingReply;
184 : bool mProcessingSyncMessage;
185 : Message mRecvd;
186 : // This is only accessed from the worker thread; seqno's are
187 : // completely opaque to the IO thread.
188 : int32 mNextSeqno;
189 :
190 : static bool sIsPumpingMessages;
191 :
192 : // Timeout periods are broken up in two to prevent system suspension from
193 : // triggering an abort. This method (called by WaitForNotify with a 'did
194 : // timeout' flag) decides if we should wait again for half of mTimeoutMs
195 : // or give up.
196 : bool WaitResponse(bool aWaitTimedOut);
197 : bool mInTimeoutSecondHalf;
198 : int32 mTimeoutMs;
199 :
200 : #ifdef OS_WIN
201 : HANDLE mEvent;
202 : #endif
203 :
204 : private:
205 : bool EventOccurred();
206 : };
207 :
208 :
209 : } // namespace ipc
210 : } // namespace mozilla
211 : #endif // ifndef ipc_glue_SyncChannel_h
|