Ejemplo n.º 1
0
void
RPCChannel::MaybeUndeferIncall()
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();

    if (mDeferred.empty())
        return;

    size_t stackDepth = StackDepth();

    // the other side can only *under*-estimate our actual stack depth
    RPC_ASSERT(mDeferred.top().rpc_remote_stack_depth_guess() <= stackDepth,
               "fatal logic error");

    if (mDeferred.top().rpc_remote_stack_depth_guess() < RemoteViewOfStackDepth(stackDepth))
        return;

    // maybe time to process this message
    Message call = mDeferred.top();
    mDeferred.pop();

    // fix up fudge factor we added to account for race
    RPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
    --mRemoteStackDepthGuess;

    mPending.push_back(call);
}
Ejemplo n.º 2
0
void
RPCChannel::OnChannelErrorFromLink()
{
    AssertLinkThread();
    mMonitor->AssertCurrentThreadOwns();

    if (0 < StackDepth())
        NotifyWorkerThread();

    SyncChannel::OnChannelErrorFromLink();
}
Ejemplo n.º 3
0
bool
RPCChannel::EventOccurred() const
{
    AssertWorkerThread();
    mMonitor->AssertCurrentThreadOwns();
    RPC_ASSERT(StackDepth() > 0, "not in wait loop");

    return (!Connected() ||
            !mPending.empty() ||
            !mUrgent.empty() ||
            (!mOutOfTurnReplies.empty() &&
             mOutOfTurnReplies.find(mStack.top().seqno())
             != mOutOfTurnReplies.end()));
}
Ejemplo n.º 4
0
static void DisplayStack(stackADT stack) 
{
  int i, depth;
  printf("Stos: ");
  depth=StackDepth(stack);
  if (depth==0) {
    printf("pusty\n");
  } else {
    for (i=depth-1;i>=0; i--) {
      if (i<depth-1) printf(" ");
      printf("%g", GetStackElement(stack,i));
    }
    printf("\n");
  }
}
Ejemplo n.º 5
0
bool
RPCChannel::Call(Message* _msg, Message* reply)
{
    RPC_ASSERT(!mPendingReply, "should not be waiting for a reply");

    nsAutoPtr<Message> msg(_msg);
    AssertWorkerThread();
    mMonitor->AssertNotCurrentThreadOwns();
    RPC_ASSERT(!ProcessingSyncMessage() || msg->priority() == IPC::Message::PRIORITY_HIGH,
               "violation of sync handler invariant");
    RPC_ASSERT(msg->is_rpc(), "can only Call() RPC messages here");

#ifdef OS_WIN
    SyncStackFrame frame(this, true);
#endif

    Message copy = *msg;
    CxxStackFrame f(*this, OUT_MESSAGE, &copy);

    MonitorAutoLock lock(*mMonitor);

    if (!Connected()) {
        ReportConnectionError("RPCChannel");
        return false;
    }

    bool urgent = (copy.priority() == IPC::Message::PRIORITY_HIGH);

    msg->set_seqno(NextSeqno());
    msg->set_rpc_remote_stack_depth_guess(mRemoteStackDepthGuess);
    msg->set_rpc_local_stack_depth(1 + StackDepth());
    mStack.push(*msg);

    mLink->SendMessage(msg.forget());

    while (1) {
        // if a handler invoked by *Dispatch*() spun a nested event
        // loop, and the connection was broken during that loop, we
        // might have already processed the OnError event. if so,
        // trying another loop iteration will be futile because
        // channel state will have been cleared
        if (!Connected()) {
            ReportConnectionError("RPCChannel");
            return false;
        }

        // now might be the time to process a message deferred because
        // of race resolution
        MaybeUndeferIncall();

        // here we're waiting for something to happen. see long
        // comment about the queue in RPCChannel.h
        while (!EventOccurred()) {
            bool maybeTimedOut = !RPCChannel::WaitForNotify();

            if (EventOccurred() ||
                    // we might have received a "subtly deferred" message
                    // in a nested loop that it's now time to process
                    (!maybeTimedOut &&
                     (!mDeferred.empty() || !mOutOfTurnReplies.empty())))
                break;

            if (maybeTimedOut && !ShouldContinueFromTimeout())
                return false;
        }

        if (!Connected()) {
            ReportConnectionError("RPCChannel");
            return false;
        }

        Message recvd;
        MessageMap::iterator it;
        if (!mOutOfTurnReplies.empty() &&
                ((it = mOutOfTurnReplies.find(mStack.top().seqno())) !=
                 mOutOfTurnReplies.end())) {
            recvd = it->second;
            mOutOfTurnReplies.erase(it);
        }
        else if (!mUrgent.empty()) {
            recvd = mUrgent.front();
            mUrgent.pop_front();
        }
        else if (!mPending.empty()) {
            recvd = mPending.front();
            mPending.pop_front();
        }
        else {
            // because of subtleties with nested event loops, it's
            // possible that we got here and nothing happened.  or, we
            // might have a deferred in-call that needs to be
            // processed.  either way, we won't break the inner while
            // loop again until something new happens.
            continue;
        }

        if (!recvd.is_rpc()) {
            if (urgent && recvd.priority() != IPC::Message::PRIORITY_HIGH) {
                // If we're waiting for an urgent reply, don't process any
                // messages yet.
                mNonUrgentDeferred.push_back(recvd);
            } else if (recvd.is_sync()) {
                RPC_ASSERT(mPending.empty(),
                           "other side should have been blocked");
                MonitorAutoUnlock unlock(*mMonitor);
                CxxStackFrame f(*this, IN_MESSAGE, &recvd);
                SyncChannel::OnDispatchMessage(recvd);
            } else {
                MonitorAutoUnlock unlock(*mMonitor);
                CxxStackFrame f(*this, IN_MESSAGE, &recvd);
                AsyncChannel::OnDispatchMessage(recvd);
            }
            continue;
        }

        RPC_ASSERT(recvd.is_rpc(), "wtf???");

        if (recvd.is_reply()) {
            RPC_ASSERT(0 < mStack.size(), "invalid RPC stack");

            const Message& outcall = mStack.top();

            // in the parent, seqno's increase from 0, and in the
            // child, they decrease from 0
            if ((!mChild && recvd.seqno() < outcall.seqno()) ||
                    (mChild && recvd.seqno() > outcall.seqno())) {
                mOutOfTurnReplies[recvd.seqno()] = recvd;
                continue;
            }

            // FIXME/cjones: handle error
            RPC_ASSERT(
                recvd.is_reply_error() ||
                (recvd.type() == (outcall.type()+1) &&
                 recvd.seqno() == outcall.seqno()),
                "somebody's misbehavin'", "rpc", true);

            // we received a reply to our most recent outstanding
            // call.  pop this frame and return the reply
            mStack.pop();

            bool isError = recvd.is_reply_error();
            if (!isError) {
                *reply = recvd;
            }

            if (0 == StackDepth()) {
                RPC_ASSERT(
                    mOutOfTurnReplies.empty(),
                    "still have pending replies with no pending out-calls",
                    "rpc", true);
            }

            // finished with this RPC stack frame
            return !isError;
        }

        // in-call.  process in a new stack frame.

        // "snapshot" the current stack depth while we own the Monitor
        size_t stackDepth = StackDepth();
        {
            MonitorAutoUnlock unlock(*mMonitor);
            // someone called in to us from the other side.  handle the call
            CxxStackFrame f(*this, IN_MESSAGE, &recvd);
            Incall(recvd, stackDepth);
            // FIXME/cjones: error handling
        }
    }

    return true;
}
Ejemplo n.º 6
0
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));
        }
    }
}
Ejemplo n.º 7
0
bool PyrGC::ListSanity()
{
	bool found;

	if (StackDepth() < 0) {
		fprintf(stderr, "stack underflow %d\n", (int)StackDepth());
		return false;
	}

	//postfl("PyrGC::ListSanity\n");
	for (int i=0; i<kNumGCSets; ++i) {
		PyrObjectHdr *obj;
		GCSet* set = mSets + i;

		// check black marker
		obj = &set->mBlack;
		if (!IsMarker(obj)) {
			//debugf("set %d black marker color wrong %d %p\n", i, obj->gc_color, obj);
			fprintf(stderr, "set %d black marker color wrong %d %p\n", i, obj->gc_color, obj);
			setPostFile(stderr);
			DumpBackTrace(mVMGlobals);
			dumpBadObject((PyrObject*)obj);
			return false;
		}

		// check white marker
		obj = &set->mWhite;
		if (!IsMarker(obj)) {
			//debugf("set %d white marker color wrong %d %p\n", i, obj->gc_color, obj);
			fprintf(stderr, "set %d white marker color wrong %d %p\n", i, obj->gc_color, obj);
			setPostFile(stderr);
			DumpBackTrace(mVMGlobals);
			dumpBadObject((PyrObject*)obj);
			return false;
		}

		// check free pointer between white and black marker
		if (set->mFree != &set->mBlack) {
			obj = set->mWhite.next;
			found = false;
			while (!IsMarker(obj)) {
				if (obj == set->mFree) { found = true; break; }
				obj = obj->next;
			}
			if (!found) {
				//debugf("set %d free pointer not between white and black\n", i);
				fprintf(stderr, "set %d free pointer not between white and black\n", i);
				fprintf(stderr, "set->mFree %p\n", set->mFree);
				fprintf(stderr, "set->mWhite %p\n", &set->mWhite);
				fprintf(stderr, "set->mBlack %p\n", &set->mBlack);
				setPostFile(stderr);
				DumpBackTrace(mVMGlobals);
				dumpBadObject((PyrObject*)set->mFree);

				fprintf(stderr, "black %d white %d grey %d\n", mBlackColor, mWhiteColor, mGreyColor);

				obj = &set->mWhite;
				int count = 0;
				do {
					if (obj == set->mFree) fprintf(stderr, "%4d %p %3d %d FREE\n", count, obj, obj->gc_color, obj->obj_sizeclass);
					else if (obj == &set->mWhite) fprintf(stderr, "%4d %p %3d %d WHITE\n", count, obj, obj->gc_color, obj->obj_sizeclass);
					else if (obj == &set->mBlack) fprintf(stderr, "%4d %p %3d %d BLACK\n", count, obj, obj->gc_color, obj->obj_sizeclass);
					else fprintf(stderr, "%4d %p %3d %d\n", count, obj, obj->gc_color, obj->obj_sizeclass);
					obj = obj->next;
					count++;
				} while (obj != &set->mWhite);

				return false;
			}
		}

		// scan black list
		obj = set->mBlack.next;
		while (!IsMarker(obj)) {
			if (obj->gc_color != mBlackColor) {
				//debugf("set %d black list obj color wrong %d (%d, %d, %d) %p\n",
				//	i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj);
				fprintf(stderr, "set %d black list obj color wrong %d (%d, %d, %d) %p\n",
					i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj);
				setPostFile(stderr);
				DumpBackTrace(mVMGlobals);
				dumpBadObject((PyrObject*)obj);
				return false;
			}
			if (GetGCSet(obj) != set) {
				//debugf("set %d black obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
				fprintf(stderr, "set %d black obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
				setPostFile(stderr);
				dumpBadObject((PyrObject*)obj);
				return false;
			}
			if (obj->next->prev != obj) {
				fprintf(stderr, "set %d black obj->next->prev != obj\n", i);
				setPostFile(stderr);
				DumpBackTrace(mVMGlobals);
				dumpBadObject((PyrObject*)obj);
			}

			// scan for refs to white.
			if (!BlackToWhiteCheck((PyrObject*)obj)) return false;

			obj = obj->next;
		}

		// scan white list
		obj = set->mWhite.next;
		while (obj != set->mFree) {
			if (obj->gc_color != mWhiteColor) {
				//debugf("set %d white list obj color wrong %d (%d, %d, %d) %p\n",
				//	i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj);
				//debugf("hmmm free %p  black %p\n", set->mFree, set->black);
				fprintf(stderr, "set %d white list obj color wrong %d (%d, %d, %d) %p\n",
					i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj);
				fprintf(stderr, "hmmm free %p  black %p\n", set->mFree, &set->mBlack);
				setPostFile(stderr);
				DumpBackTrace(mVMGlobals);
				dumpBadObject((PyrObject*)obj);
				return false;
			}
			if (GetGCSet(obj) != set) {
				//debugf("set %d white obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
				fprintf(stderr, "set %d white obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
				setPostFile(stderr);
				DumpBackTrace(mVMGlobals);
				dumpBadObject((PyrObject*)obj);
				return false;
			}
			if (obj->next->prev != obj) {
				fprintf(stderr, "set %d white obj->next->prev != obj\n", i);
				setPostFile(stderr);
				DumpBackTrace(mVMGlobals);
				dumpBadObject((PyrObject*)obj);
			}
			obj = obj->next;
		}

		// mark all free list items free
		obj = set->mFree;
		while (!IsMarker(obj)) {
			/*if (obj->gc_color == mGreyColor) {
				//debugf("grey obj on free list\n");
				fprintf(stderr, "grey obj on free list\n");
				return false;
			}*/
			//post("FREE\n");
			//dumpObject((PyrObject*)(PyrObject*)obj);
			obj->gc_color = mFreeColor;
			if (GetGCSet(obj) != set) {
				//debugf("set %d free obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
				fprintf(stderr, "set %d free obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
				//dumpObject((PyrObject*)obj);
				return false;
			}
			if (obj->next->prev != obj) {
				fprintf(stderr, "set %d free obj->next->prev != obj\n", i);
				//dumpObject((PyrObject*)obj);
			}
			obj = obj->next;
		}
	}

	int numgrey = 0;
	PyrObjectHdr *grey = mGrey.next;
	while (!IsMarker(grey)) {
		numgrey++;
		if (!IsGrey(grey)) {
			fprintf(stderr, "sc Object on grey list not grey  %d %d   %d\n", grey->gc_color, mGreyColor, numgrey);
			fprintf(stderr, "%p <- %p -> %p grey %p process %p\n", mGrey.prev, &mGrey, mGrey.next, grey, mProcess);
			return false;
		}
		grey = grey->next;
	}

	if (numgrey != mNumGrey) {
		fprintf(stderr, "grey count off %d %d\n", numgrey, mNumGrey);
		DumpInfo();
		fprintf(stderr, ".");
		return false;
	}
	return true;
}