GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — ios/NativeScript/runtime/Messaging.h at main · NativeScript/ios Expand file tree/ Copy pathMessaging.hMore file actions 234 lines (191 loc) · 9.5 KB / Copy pathMessaging.hFile metadata and controls234 lines (191 loc) · 9.5 KB 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 #ifndef Messaging_h #define Messaging_h #include <atomic> #include <deque> #include <memory> #include <mutex> #include <string> #include "Common.h" #include "IsolateWrapper.h" namespace tns { class EventLoop; namespace serialization { class SerializedValue; } namespace messaging { class NativeMessagePort; class SiblingGroup; // What a port's group did with a message handed to it. enum class DispatchResult { // Queued on at least one destination. kDelivered, // The group has no other member; the message is dropped. kNoDestination, // Nothing was queued and the caller must not treat the send as done: the // port is not entangled, or the message carries transferables and the group // has more than one destination. The out-parameter says which. kFailed, }; // Everything about a port that is not tied to an isolate, so it can be moved // into a message and adopted on the receiving side. // // `mutex_` is the only lock a producer on a foreign thread ever takes. Lock // order across the whole subsystem is SiblingGroup's lock FIRST, a port's // mutex_ second; never the reverse. Every path that needs both — dispatch, // entangle, disentangle — is entered through the group. class PortData { public: explicit PortData(NativeMessagePort* owner); ~PortData(); PortData(const PortData&) = delete; PortData& operator=(const PortData&) = delete; // The one cross-thread entry point. Appends `message` and wakes the owning // port while STILL holding the mutex, so a port detaching concurrently // either takes the mutex first and is never woken, or waits and observes the // queued message. void AddToIncomingQueue( std::shared_ptr<serialization::SerializedValue> message); // Hands `message` to every other member of this port's group. DispatchResult Dispatch( std::shared_ptr<serialization::SerializedValue> message, std::string* error); // Connects the two ends of a fresh channel. Neither end may already belong // to a group. static void Entangle(PortData* a, PortData* b); // Leaves the group, queueing a close sentinel on this port and — for an // anonymous pair — on the sibling left behind. Once this returns, no other // thread can reach this object through the group. Owner thread only. void Disentangle(); private: friend class NativeMessagePort; friend class SiblingGroup; std::mutex mutex_; std::deque<std::shared_ptr<serialization::SerializedValue>> incoming_; NativeMessagePort* owner_ = nullptr; std::shared_ptr<SiblingGroup> group_; }; // The isolate-bound half of a port: the JS wrapper, the delivery callout and // the drain that runs on the owning runtime's event loop. Home-thread only, // TriggerAsync excepted. class NativeMessagePort : public std::enable_shared_from_this<NativeMessagePort> { public: ~NativeMessagePort(); NativeMessagePort(const NativeMessagePort&) = delete; NativeMessagePort& operator=(const NativeMessagePort&) = delete; // Creates a port and its JS wrapper. With `data` the port adopts an // in-flight port — the group travels with the data — and schedules a drain // of whatever queued up while it was in transit; with `group` it joins that // named group as a BroadcastChannel's port; with neither it is one // unentangled end of a new channel. Null with an exception pending when the // wrapper or the JS tier could not be built. static std::shared_ptr<NativeMessagePort> New( v8::Local<v8::Context> context, std::unique_ptr<PortData> data = nullptr, std::shared_ptr<SiblingGroup> group = nullptr); // Schedules a drain. Any thread; the caller must hold this port's data // mutex, which is what keeps the port from detaching underneath the post. void TriggerAsync(); // HTML's port message queue enable/disable. Starting a port with a backlog // schedules a drain for it. void Start(); void Stop(); // Any thread, under this port's data mutex: whether a message queued now // would be taken by a drain, so a producer can skip waking a port that // would only find it has nothing it may deliver. bool WantsDrainFor(const serialization::SerializedValue& message) const; // A BroadcastChannel port's delivery target: the channel, held strongly, // while it has a 'message' or 'messageerror' listener; empty otherwise, and // a message drained with no target is discarded without being read. void SetBroadcastTarget(v8::Local<v8::Object> target); // Detaches the data, sentinels the sibling, drops the JS wrapper and fires // the tier's close event on it. Safe to call on an already-closed port, and // safe to call from inside that event. void Close(); // Drops the data out of the port and out of its group, so nothing can reach // it any more. What the teardown sweep does to a port app code never closed. void OrphanData(); // Pops one message regardless of whether the port was started // (receiveMessageOnPort). Just(false) when the queue holds nothing // deliverable, Just(true) with `out` set otherwise, Nothing when the value // could not be read. v8::Maybe<bool> ReceiveOne(v8::Local<v8::Context> context, v8::Local<v8::Value>* out); // The [[Detached]] internal slot. bool IsDetached() const { return this->data_ == nullptr; } // Moves the data into a message. The handle side closes, but the data keeps // its group membership and its queue: senders keep queueing into it while it // is in flight, and with no owner nothing is woken. std::unique_ptr<PortData> TransferForMessaging(); // Empty once the port has been closed. v8::Local<v8::Object> Wrapper(v8::Isolate* isolate) const; PortData* Data() const { return this->data_.get(); } private: NativeMessagePort(v8::Isolate* isolate, v8::Local<v8::Object> wrapper); std::unique_ptr<PortData> Detach(); void CloseHandle(); void EmitClose(v8::Local<v8::Object> wrapper); void Drain(); std::shared_ptr<serialization::SerializedValue> TakeMessage(bool force); bool Emit(v8::Local<v8::Context> context, v8::Local<v8::Object> receiver, v8::Local<v8::Function> emitMessage, v8::Local<v8::Value> data, v8::Local<v8::Value> ports, const char* type); std::unique_ptr<PortData> data_; // Written on the home thread only; producers read it in WantsDrainFor. std::atomic<bool> receiving_{false}; // Set once, at creation. A broadcast port always receives; whether a message // is delivered or discarded is decided per message by broadcastTarget_. bool broadcast_ = false; // Set while a drain is queued, so a burst of messages costs one post. // Atomic because producers flip it from their own threads. std::atomic<bool> scheduled_{false}; // Strong on purpose: a port and its JS wrapper stay alive until the port is // closed, which is the lifetime model HTML and Node specify — reachability // plays no part in it. v8::Global<v8::Object> wrapper_; v8::Global<v8::Object> broadcastTarget_; IsolateWrapper isolateWrapper_; // Held by shared_ptr so a drain posted from a foreign thread can never race // the loop's own teardown. std::shared_ptr<EventLoop> loop_; }; // The port behind a JS wrapper, or null when `object` is not a port wrapper or // its port has been closed. NativeMessagePort* PortFromWrapper(v8::Isolate* isolate, v8::Local<v8::Object> object); // Whether `object` is a MessagePort wrapper at all, closed or not. The // serializer needs the distinction: a closed port in a transfer list is a // different error from a value that was never transferable. bool IsPortWrapper(v8::Isolate* isolate, v8::Local<v8::Object> object); // Adopts an in-flight port on this isolate and returns its fresh wrapper. v8::MaybeLocal<v8::Object> AdoptPort(v8::Local<v8::Context> context, std::unique_ptr<PortData> data); // The markAsUntransferable / markAsUncloneable brands. Both answer Just(false) // without creating anything when this isolate has never stamped one. v8::Maybe<bool> IsMarkedUntransferable(v8::Isolate* isolate, v8::Local<v8::Object> object); v8::Maybe<bool> IsMarkedUncloneable(v8::Isolate* isolate, v8::Local<v8::Object> object); // The markAsUncloneable brand itself, empty when this isolate has never // stamped one. For the serializer, which is asked about every object in a // claimed graph and hoists the lookup out of that loop. v8::Local<v8::Private> UncloneableBrandIfAny(v8::Isolate* isolate); // The natives behind the message-channel builtin: channel and port // primitives, the two registration hooks the JS tier calls once per isolate, // and the transfer brands. v8::MaybeLocal<v8::Object> CreateBinding(v8::Local<v8::Context> context); // The two builtins' exports with that binding attached. GetExports consults // the factory only on the run that populates the cache, so every call site for // these builtins must go through here — a site passing a different factory // would win or lose by init order. v8::MaybeLocal<v8::Object> GetMessageChannelExports( v8::Local<v8::Context> context); v8::MaybeLocal<v8::Object> GetBroadcastChannelExports( v8::Local<v8::Context> context); // Force-closes every port this isolate still owns: the data is orphaned and // disentangled, so siblings on other isolates get their close sentinels and // nothing can reach this isolate's ports afterwards. Must run after the event // loop has stopped and while the isolate is still locked. void CloseAllPorts(v8::Isolate* isolate); } // namespace messaging } // namespace tns #endif /* Messaging_h */ |
| You are visitor 01402520 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |