Beispiel #1
0
void SendIPCMessage(ipc_message_t msg, bool blocking) {
    MessageQueue* q = msg.ConsumableEarly() ? ipcEarlyMessageQueue : ipcMessageQueue;
    msg.blocking = blocking;

#ifdef IPC_DEBUG
    lk_lock(printing_lock, 1);
    std::cerr << "[SEND] IPC message, ID: " << msg.id << std::endl;
    lk_unlock(printing_lock);
#endif

    lk_lock(lk_ipcMessageQueue, 1);
    q->push_back(msg);

    if (blocking)
        ackMessages->operator[](msg) = false;
    lk_unlock(lk_ipcMessageQueue);

    if (blocking) {
        lk_lock(lk_ipcMessageQueue, 1);
        while (ackMessages->at(msg) == false) {
            lk_unlock(lk_ipcMessageQueue);
            xio_sleep(10);
            lk_lock(lk_ipcMessageQueue, 1);
        }
        lk_unlock(lk_ipcMessageQueue);
    }
}
void
RPCChannel::OnMessageReceivedFromLink(const Message& msg)
{
    AssertLinkThread();
    mMonitor->AssertCurrentThreadOwns();

    if (MaybeInterceptSpecialIOMessage(msg))
        return;

    // regardless of the RPC stack, if we're awaiting a sync reply, we
    // know that it needs to be immediately handled to unblock us.
    if (AwaitingSyncReply() && msg.is_sync()) {
        // wake up worker thread waiting at SyncChannel::Send
        mRecvd = msg;
        NotifyWorkerThread();
        return;
    }

    MessageQueue *queue = (msg.priority() == IPC::Message::PRIORITY_HIGH)
                          ? &mUrgent
                          : &mPending;

    bool compressMessage = (msg.compress() && !queue->empty() &&
                            queue->back().type() == msg.type() &&
                            queue->back().routing_id() == msg.routing_id());
    if (compressMessage) {
        // This message type has compression enabled, and the back of
        // the queue was the same message type and routed to the same
        // destination.  Replace it with the newer message.
        MOZ_ASSERT(queue->back().compress());
        queue->pop_back();
    }

    queue->push_back(msg);

    // There are three cases we're concerned about, relating to the state of
    // the main thread:
    //
    // (1) We are waiting on a sync reply - main thread is blocked on the IPC monitor.
    //   - If the message is high priority, we wake up the main thread to
    //     deliver the message. Otherwise, we leave it in the mPending queue,
    //     posting a task to the main event loop, where it will be processed
    //     once the synchronous reply has been received.
    //
    // (2) We are waiting on an RPC reply - main thread is blocked on the IPC monitor.
    //   - Always wake up the main thread to deliver the message.
    //
    // (3) We are not waiting on a reply.
    //   - We post a task to the main event loop.
    //
    bool waiting_rpc = (0 != StackDepth());
    bool urgent = (msg.priority() == IPC::Message::PRIORITY_HIGH);

    if (waiting_rpc || (AwaitingSyncReply() && urgent)) {
        // Always wake up our RPC waiter, and wake up sync waiters for urgent
        // messages.
        NotifyWorkerThread();
    } else {
        // Worker thread is either not blocked on a reply, or this is an
        // incoming RPC that raced with outgoing sync and needs to be deferred
        // to a later event-loop iteration.
        if (!compressMessage) {
            // If we compressed away the previous message, we'll reuse
            // its pending task.
            mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
        }
    }
}
/******************************* test functions *******************************/
int32_t ut_MessageQueue_simple(void)
{
	TestCaseBegin();

	std::mutex mMut;

	std::atomic_int mInt;
	mInt = 0;
	std::atomic_char running;
	running = 1;

	MessageQueue < std::function < int(void) >> messages;

	std::thread t1([&]
		{
			while(running)
			{
				const auto f = messages.receive();
				if(f) mInt = f();
				std::this_thread::sleep_for(std::chrono::milliseconds(10));
			}
		}
		);

	CHECK(0 == mInt);

	messages.push_back([ = ] {return 1; }
			   );
	std::this_thread::sleep_for(std::chrono::milliseconds(20));
	CHECK(1 == mInt);

	messages.push_back([ = ] {return 2; }
			   );
	std::this_thread::sleep_for(std::chrono::milliseconds(20));
	CHECK(2 == mInt);

	messages.push_back([ = ] {return 4; }
			   );
	messages.push_front([ = ] {return 3; }
			    );
	std::this_thread::sleep_for(std::chrono::milliseconds(5));
	CHECK(3 == mInt);
	std::this_thread::sleep_for(std::chrono::milliseconds(10));
	CHECK(4 == mInt);

	{
		std::lock_guard<std::mutex> lg(mMut);
		messages.push_back([ = ] {return 5; }
				   );
		messages.push_back([ = ] {return 5; }
				   );
		messages.push_back([ = ] {return 5; }
				   );
		messages.clear_and_push_front([ = ] {return 6; }
					      );
	}
	std::this_thread::sleep_for(std::chrono::milliseconds(20));
	CHECK(6 == mInt);
	std::this_thread::sleep_for(std::chrono::milliseconds(10));
	CHECK(6 == mInt);

	messages.push_back([ = ] {return 5; }
			   );
	running = 0;
	t1.join();

	TestCaseEnd();
}
int32_t ut_MessageQueue_complex(void)
{
	TestCaseBegin();

	std::mutex mMut;

	std::atomic_int mInt;
	mInt = 0;

	MessageQueue < std::pair < std::function<int(void)>, bool >> messages;

	std::thread t1([&]
		{
			while(true)
			{
				const auto f = messages.receive();
				if(f.second) break;
				if(f.first) mInt = f.first();
				std::this_thread::sleep_for(std::chrono::milliseconds(50));
			}
		}
		);

	CHECK(0 == mInt);

	messages.push_back(std::make_pair([ = ] {return 1; }, false));
	std::this_thread::sleep_for(std::chrono::milliseconds(100));
	CHECK(1 == mInt);

	messages.push_back(std::make_pair([ = ] {return 2; }, false));
	std::this_thread::sleep_for(std::chrono::milliseconds(100));
	CHECK(2 == mInt);

	messages.push_back(std::make_pair([ = ] {return 4; }, false));
	messages.push_back(std::make_pair([ = ] {return 5; }, false));
	messages.push_front(std::make_pair([ = ] {return 3; }, false));
	std::this_thread::sleep_for(std::chrono::milliseconds(40));
	CHECK(3 == mInt);
	std::this_thread::sleep_for(std::chrono::milliseconds(50));
	CHECK(4 == mInt);
	std::this_thread::sleep_for(std::chrono::milliseconds(50));
	CHECK(5 == mInt);


	{
		std::lock_guard<std::mutex> lg(mMut);
		messages.push_back(std::make_pair([ = ] {return 4; }, false));
		messages.push_back(std::make_pair([ = ] {return 4; }, false));
		messages.push_back(std::make_pair([ = ] {return 4; }, false));
		messages.clear_and_push_front(std::make_pair([ = ] {return 6; }, false));
	}
	std::this_thread::sleep_for(std::chrono::milliseconds(50));
	CHECK(6 == mInt);
	std::this_thread::sleep_for(std::chrono::milliseconds(50));
	CHECK(6 == mInt);

	messages.push_front(std::make_pair([ = ] {return 0xff; }, true));
	std::this_thread::sleep_for(std::chrono::milliseconds(10));
	t1.join();

	TestCaseEnd();
}