Example #1
0
 public InboxRef(string name, int maxMsgSize)
 {
     this.name          = name;
     this.maxMsgSize    = maxMsgSize;
     this.inbox         = null;
     this.emptyBoxEvent = null;
 }
Example #2
0
        /// <summary>
        /// This method initializes a shared memory inbox by creating one if
        /// it doesn't already exist or opening it if it does exist.  Note that
        /// all successful calls to Open() must be matched with a call to
        /// <see cref="Close" />. Note that to avoid problems, only one process
        /// may open an inbox using the SharedMemInbox class.  This method is threadsafe.
        /// </summary>
        /// <param name="name">
        /// Name of the inbox.  This can be a maximum of 128 characters and may
        /// not include the backslash (\) character.  The name is case sensitive.
        /// </param>
        /// <param name="maxMsgSize">
        /// Maximum message size allowed in bytes.  Note that this parameter must be
        /// the same across all instances of SharedMemInbox and SharedMemOutBox
        /// classes accessing this inbox.
        /// </param>
        /// <param name="onReceive">
        /// Delegate to be called when a message is placed in the inbox.  Note that
        /// this method will be called on a pool thread.
        /// </param>
        public unsafe void Open(string name, int maxMsgSize, SharedMemInboxReceiveDelegate onReceive)
        {
            if (name.Length > 128)
            {
                throw new ArgumentException("Name exceeds 128 characters.", "name");
            }

            if (name.IndexOfAny(new char[] { '/', '\\' }) != -1)
            {
                throw new ArgumentException("Name may not include forward or backslashes.");
            }

            if (maxMsgSize <= 0)
            {
                throw new ArgumentException("Invalid maximum message size.", "maxMsgSize");
            }

            lock (syncLock)
            {
                if (this.sharedMem != null)
                {
                    return;     // Already open
                }
                this.maxMsgSize = maxMsgSize;
                this.onReceive  = onReceive;
                this.onDispatch = new WaitCallback(OnDispatch);
                this.sharedMem  = new SharedMem();
                this.sharedMem.Open(name, maxMsgSize + MemHeaderSize, SharedMem.OpenMode.CREATE_OPEN);

                // Here's what the abbreviations mean:
                //
                //      LT  = LillTek
                //      SMI = SharedMemInBox
                //      NME = NewMessageEvent
                //      EBE = EmptyBoxEvent

                this.newMsgEvent   = new GlobalAutoResetEvent("LT:SMI:NME:" + name);
                this.emptyBoxEvent = new GlobalAutoResetEvent("LT:SMI:EBE:" + name);
                this.killThread    = false;
#if WINFULL
                this.recvThread = new Thread(new ThreadStart(ReceiveThreadProc));
#else
                this.recvThread = new CEThread(new ThreadStart(ReceiveThreadProc));
#endif
                this.recvThread.Start();

                byte *p;

                p = sharedMem.Lock();
                *(int *)&p[MaxMsgSizeOffset] = maxMsgSize;
                *(int *)&p[CurMsgSizeOffset] = 0;
                p[InboxListeningOffset]      = 1;
                sharedMem.Unlock();

                emptyBoxEvent.Set();
            }
        }
Example #3
0
            /// <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);
            }