/// <summary> /// This method implements the background thread that waits for inbound messages. /// </summary> private unsafe void ReceiveThreadProc() { byte[] msg; int cb; byte * p; while (!killThread) { msg = null; #if WINCE newMsgEvent.WaitOne(); if (killThread) { break; } #else bool signal; signal = newMsgEvent.WaitOne(1000, false); if (killThread) { break; } if (!signal) { continue; } #endif p = sharedMem.Lock(); cb = *(int *)&p[CurMsgSizeOffset]; if (0 < cb && cb <= maxMsgSize) { msg = new byte[cb]; for (int i = 0; i < cb; i++) { msg[i] = p[i + MessageOffset]; } } sharedMem.Unlock(); emptyBoxEvent.Set(); if (msg != null) { Helper.UnsafeQueueUserWorkItem(onDispatch, msg); } } }
/// <summary> /// This method transmits the byte message array passed to the inbox. Note that /// you may pass <paramref name="message" /> as <c>null</c>. In this case, the method will simply detect /// whether or not the inbox exists and is able to accept a message transmission. /// </summary> /// <param name="message">The message array.</param> /// <param name="maxWait">The maximum time to wait for the transmission to complete.</param> /// <returns><c>true</c> if the operation was successful.</returns> public unsafe bool Send(byte[] message, TimeSpan maxWait) { // See the comment in SharedMemInbox for a description of the // shared memory block format. byte *p; if (message != null && message.Length > maxMsgSize) { throw new ArgumentException("Message is too large.", "message"); } lock (syncLock) { if (inbox == null) { // Initialize the inbox reference. Return <c>false</c> if the inbox // shared memory does not exist or if there's no SharedMemInbox // listening. try { inbox = new SharedMem(); inbox.Open(name, maxMsgSize, SharedMem.OpenMode.OPEN_ONLY); } catch { inbox = null; return(false); } // Here's what the abbreviations mean: // // LT = LillTek // SMI = SharedMemInBox // NME = NewMessageEvent // EBE = EmptyBoxEvent newMsgEvent = new GlobalAutoResetEvent("LT:SMI:NME:" + name); emptyBoxEvent = new GlobalAutoResetEvent("LT:SMI:EBE:" + name); } // Wait for exclusive access to an empty shared memory block and then // send the message. if (emptyBoxEvent == null || !emptyBoxEvent.WaitOne(maxWait, false)) { // $todo: I really shouldn't have to close the inbox here but for // some reason, the emptyBoxEvent is never set in some // situations (like when a service router starts before the // zone or machine router on the computer). At some point, // I'd like to come back and investigate why this is happening. inbox.Close(); newMsgEvent.Close(); emptyBoxEvent.Close(); inbox = null; newMsgEvent = null; emptyBoxEvent = null; return(false); } if (message == null) { emptyBoxEvent.Set(); return(true); } p = inbox.Lock(); try { int cbMax; if (p[SharedMemInbox.InboxListeningOffset] == 0) { return(false); // There's no inbox listening } cbMax = *(int *)&p[SharedMemInbox.MaxMsgSizeOffset]; if (cbMax != maxMsgSize) { throw new Exception("SharedMemInbox MaxMsgSize mismatch."); } for (int i = 0; i < message.Length; i++) { p[SharedMemInbox.MessageOffset + i] = message[i]; } *(int *)&p[SharedMemInbox.CurMsgSizeOffset] = message.Length; newMsgEvent.Set(); } finally { inbox.Unlock(); } } return(true); }