diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 57a32e75370a..0cd2bb16a0b3 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -316,7 +316,6 @@ MessageChannel::MessageChannel(MessageListener *aListener) mTimeoutMs(kNoTimeout), mInTimeoutSecondHalf(false), mNextSeqno(0), - mLastSendError(SyncSendError::SendSuccess), mAwaitingSyncReply(false), mAwaitingSyncReplyPriority(0), mDispatchingSyncMessage(false), @@ -324,7 +323,6 @@ MessageChannel::MessageChannel(MessageListener *aListener) mDispatchingAsyncMessage(false), mDispatchingAsyncMessagePriority(0), mCurrentTransaction(0), - mPendingSendPriorities(0), mTimedOutMessageSeqno(0), mTimedOutMessagePriority(0), mRecvdErrors(0), @@ -572,10 +570,9 @@ MessageChannel::Send(Message* aMsg) class CancelMessage : public IPC::Message { public: - CancelMessage(int transaction) : + CancelMessage() : IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE, PRIORITY_NORMAL) { - set_transaction_id(transaction); } static bool Read(const Message* msg) { return true; @@ -603,9 +600,20 @@ MessageChannel::MaybeInterceptSpecialIOMessage(const Message& aMsg) return true; } else if (CANCEL_MESSAGE_TYPE == aMsg.type()) { IPC_LOG("Cancel from message"); - CancelTransaction(aMsg.transaction_id()); - NotifyWorkerThread(); - return true; + + if (aMsg.transaction_id() == mTimedOutMessageSeqno) { + // An unusual case: We timed out a transaction which the other + // side then cancelled. In this case we just leave the timedout + // state and try to forget this ever happened. + mTimedOutMessageSeqno = 0; + return true; + } else { + MOZ_RELEASE_ASSERT(mCurrentTransaction == aMsg.transaction_id()); + CancelCurrentTransactionInternal(); + NotifyWorkerThread(); + IPC_LOG("Notified"); + return true; + } } } return false; @@ -680,7 +688,7 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg) if (aMsg.seqno() == mTimedOutMessageSeqno) { // Drop the message, but allow future sync messages to be sent. IPC_LOG("Received reply to timedout message; igoring; xid=%d", mTimedOutMessageSeqno); - EndTimeout(); + mTimedOutMessageSeqno = 0; return; } @@ -773,23 +781,22 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg) if (shouldWakeUp) { NotifyWorkerThread(); - } - - // It's possible that a Send or Call call on the stack will process the - // message. However, it's difficult to ensure that Send always processes all - // messages in mPending before exiting, so it's safer to enqueue a task for - // each one. If the queue is empty, the task does nothing. - if (!compress) { - // If we compressed away the previous message, we'll re-use - // its pending task. - mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); + } else { + // Worker thread is either not blocked on a reply, or this is an + // incoming Interrupt that raced with outgoing sync, and needs to be + // deferred to a later event-loop iteration. + if (!compress) { + // If we compressed away the previous message, we'll re-use + // its pending task. + mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); + } } } void -MessageChannel::ProcessPendingRequests(int seqno, int transaction) +MessageChannel::ProcessPendingRequests(int transaction, int prio) { - IPC_LOG("ProcessPendingRequests for seqno=%d, xid=%d", seqno, transaction); + IPC_LOG("ProcessPendingRequests"); // Loop until there aren't any more priority messages to process. for (;;) { @@ -828,31 +835,50 @@ MessageChannel::ProcessPendingRequests(int seqno, int transaction) // operating with weird state (as if no Send is in progress). That could // cause even normal priority sync messages to be processed (but not // normal priority async messages), which would break message ordering. - if (WasTransactionCanceled(transaction)) { + if (WasTransactionCanceled(transaction, prio)) { return; } } } bool -MessageChannel::WasTransactionCanceled(int transaction) +MessageChannel::WasTransactionCanceled(int transaction, int prio) { - if (transaction != mCurrentTransaction) { - // Imagine this scenario: - // 1. Child sends high prio sync message H1. - // 2. Parent sends reply to H1. - // 3. Parent sends high prio sync message H2. - // 4. Child's link thread receives H1 reply and H2 before worker wakes up. - // 5. Child dispatches H2 while still waiting for H1 reply. - // 6. Child cancels H2. - // - // In this case H1 will also be considered cancelled. However, its - // reply is still sitting in mRecvd, which can trip up later Sends. So - // we null it out here. - mRecvd = nullptr; - return true; + if (transaction == mCurrentTransaction) { + return false; } - return false; + + // This isn't an assert so much as an intentional crash because we're in a + // situation that we don't know how to recover from: The child is awaiting + // a reply to a normal-priority sync message. The transaction that this + // message initiated has now been canceled. That could only happen if a CPOW + // raced with the sync message and was dispatched by the child while the + // child was awaiting the sync reply; at some point while dispatching the + // CPOW, the transaction was canceled. + // + // Notes: + // + // 1. We don't want to cancel the normal-priority sync message along with + // the CPOWs because the browser relies on these messages working + // reliably. + // + // 2. Ideally we would like to avoid dispatching CPOWs while awaiting a sync + // response. This isn't possible though. To avoid deadlock, the parent would + // have to dispatch the sync message while waiting for the CPOW + // response. However, it wouldn't have dispatched async messages at that + // time, so we would have a message ordering bug. Dispatching the async + // messages first causes other hard-to-handle situations (what if they send + // CPOWs?). + // + // 3. We would like to be able to cancel the CPOWs but not the sync + // message. However, that would leave both the parent and the child running + // code at the same time, all while the sync message is still + // outstanding. That can cause a problem where message replies are received + // out of order. + IPC_ASSERT(prio != IPC::Message::PRIORITY_NORMAL, + "Intentional crash: We canceled a CPOW that was racing with a sync message."); + + return true; } bool @@ -882,7 +908,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply) // message receives a reply, we'll be able to send more sync messages // again. IPC_LOG("Send() failed due to previous timeout"); - mLastSendError = SyncSendError::PreviousTimeout; return false; } @@ -893,7 +918,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply) // Don't allow sending CPOWs while we're dispatching a sync message. // If you want to do that, use sendRpcMessage instead. IPC_LOG("Prio forbids send"); - mLastSendError = SyncSendError::SendingCPOWWhileDispatchingSync; return false; } @@ -905,8 +929,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply) // sync messages it can send are high-priority. Mainly we want to ensure // here that we don't return false for non-CPOW messages. MOZ_ASSERT(msg->priority() == IPC::Message::PRIORITY_HIGH); - IPC_LOG("Sending while dispatching urgent message"); - mLastSendError = SyncSendError::SendingCPOWWhileDispatchingUrgent; return false; } @@ -916,9 +938,10 @@ MessageChannel::Send(Message* aMsg, Message* aReply) { MOZ_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage()); IPC_LOG("Cancel from Send"); - CancelMessage *cancel = new CancelMessage(mCurrentTransaction); - CancelTransaction(mCurrentTransaction); + CancelMessage *cancel = new CancelMessage(); + cancel->set_transaction_id(mCurrentTransaction); mLink->SendMessage(cancel); + CancelCurrentTransactionInternal(); } IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here"); @@ -937,7 +960,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply) if (!Connected()) { ReportConnectionError("MessageChannel::SendAndWait", msg); - mLastSendError = SyncSendError::NotConnectedBeforeSend; return false; } @@ -951,27 +973,24 @@ MessageChannel::Send(Message* aMsg, Message* aReply) AutoSetValue prioSet(mAwaitingSyncReplyPriority, prio); AutoEnterTransaction transact(this, seqno); - int prios = mPendingSendPriorities | (1 << prio); - AutoSetValue priosSet(mPendingSendPriorities, prios); - int32_t transaction = mCurrentTransaction; msg->set_transaction_id(transaction); - IPC_LOG("Send seqno=%d, xid=%d, pending=%d", seqno, transaction, prios); + IPC_LOG("Send seqno=%d, xid=%d", seqno, transaction); + + ProcessPendingRequests(transaction, prio); + if (WasTransactionCanceled(transaction, prio)) { + IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction); + return false; + } bool handleWindowsMessages = mListener->HandleWindowsMessages(*aMsg); mLink->SendMessage(msg.forget()); while (true) { - ProcessPendingRequests(seqno, transaction); - if (WasTransactionCanceled(transaction)) { + ProcessPendingRequests(transaction, prio); + if (WasTransactionCanceled(transaction, prio)) { IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction); - mLastSendError = SyncSendError::CancelledAfterSend; - return false; - } - if (!Connected()) { - ReportConnectionError("MessageChannel::Send"); - mLastSendError = SyncSendError::DisconnectedDuringSend; return false; } @@ -979,7 +998,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply) if (mRecvdErrors) { IPC_LOG("Error: seqno=%d, xid=%d", seqno, transaction); mRecvdErrors--; - mLastSendError = SyncSendError::ReplyError; return false; } @@ -995,13 +1013,11 @@ MessageChannel::Send(Message* aMsg, Message* aReply) if (!Connected()) { ReportConnectionError("MessageChannel::SendAndWait"); - mLastSendError = SyncSendError::DisconnectedDuringSend; return false; } - if (WasTransactionCanceled(transaction)) { + if (WasTransactionCanceled(transaction, prio)) { IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction); - mLastSendError = SyncSendError::CancelledAfterSend; return false; } @@ -1009,29 +1025,22 @@ MessageChannel::Send(Message* aMsg, Message* aReply) // if neither side has any other message Sends on the stack). bool canTimeOut = transaction == seqno; if (maybeTimedOut && canTimeOut && !ShouldContinueFromTimeout()) { - // Since ShouldContinueFromTimeout drops the lock, we need to - // re-check all our conditions here. We shouldn't time out if any of - // these things happen because there won't be a reply to the timed - // out message in these cases. - if (WasTransactionCanceled(transaction)) { - IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction); - mLastSendError = SyncSendError::CancelledAfterSend; - return false; - } + IPC_LOG("Timing out Send: xid=%d", transaction); + + // We might have received a reply during WaitForSyncNotify or inside + // ShouldContinueFromTimeout (which drops the lock). We need to make + // sure not to set mTimedOutMessageSeqno if that happens, since then + // there would be no way to unset it. if (mRecvdErrors) { mRecvdErrors--; - mLastSendError = SyncSendError::ReplyError; return false; } if (mRecvd) { break; } - IPC_LOG("Timing out Send: xid=%d", transaction); - mTimedOutMessageSeqno = seqno; mTimedOutMessagePriority = prio; - mLastSendError = SyncSendError::TimedOut; return false; } } @@ -1045,7 +1054,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply) *aReply = Move(*mRecvd); mRecvd = nullptr; - mLastSendError = SyncSendError::SendSuccess; return true; } @@ -1310,37 +1318,6 @@ MessageChannel::DequeueOne(Message *recvd) if (!mDeferred.empty()) MaybeUndeferIncall(); - // If we've timed out a message and we're awaiting the reply to the timed - // out message, we have to be careful what messages we process. Here's what - // can go wrong: - // 1. child sends a normal priority sync message S - // 2. parent sends a high priority sync message H at the same time - // 3. parent times out H - // 4. child starts processing H and sends a high priority message H' nested - // within the same transaction - // 5. parent dispatches S and sends reply - // 6. child asserts because it instead expected a reply to H'. - // - // To solve this, we refuse to process S in the parent until we get a reply - // to H. More generally, let the timed out message be M. We don't process a - // message unless the child would need the response to that message in order - // to process M. Those messages are the ones that have a higher priority - // than M or that are part of the same transaction as M. - if (mTimedOutMessageSeqno) { - for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); it++) { - Message &msg = *it; - if (msg.priority() > mTimedOutMessagePriority || - (msg.priority() == mTimedOutMessagePriority - && msg.transaction_id() == mTimedOutMessageSeqno)) - { - *recvd = Move(msg); - mPending.erase(it); - return true; - } - } - return false; - } - if (mPending.empty()) return false; @@ -1433,7 +1410,22 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply) MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy; Result rv; - { + if (mTimedOutMessageSeqno && mTimedOutMessagePriority >= prio) { + // If the other side sends a message in response to one of our messages + // that we've timed out, then we reply with an error. + // + // We do this because want to avoid a situation where we process an + // incoming message from the child here while it simultaneously starts + // processing our timed-out CPOW. It's very bad for both sides to + // be processing sync messages concurrently. + // + // The only exception is if the incoming message has urgent priority and + // our timed-out message had only high priority. In that case it's safe + // to process the incoming message because we know that the child won't + // process anything (the child will defer incoming messages when waiting + // for a response to its urgent message). + rv = MsgNotAllowed; + } else { AutoSetValue blocked(blockingVar, this); AutoSetValue sync(mDispatchingSyncMessage, true); AutoSetValue prioSet(mDispatchingSyncMessagePriority, prio); @@ -1836,8 +1828,6 @@ MessageChannel::OnChannelErrorFromLink() AssertLinkThread(); mMonitor->AssertCurrentThreadOwns(); - IPC_LOG("OnChannelErrorFromLink"); - if (InterruptStackDepth() > 0) NotifyWorkerThread(); @@ -2103,25 +2093,7 @@ MessageChannel::GetTopmostMessageRoutingId() const } void -MessageChannel::EndTimeout() -{ - mMonitor->AssertCurrentThreadOwns(); - - IPC_LOG("Ending timeout of seqno=%d", mTimedOutMessageSeqno); - mTimedOutMessageSeqno = 0; - mTimedOutMessagePriority = 0; - - for (size_t i = 0; i < mPending.size(); i++) { - // There may be messages in the queue that we expected to process from - // OnMaybeDequeueOne. But during the timeout, that function will skip - // some messages. Now they're ready to be processed, so we enqueue more - // tasks. - mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); - } -} - -void -MessageChannel::CancelTransaction(int transaction) +MessageChannel::CancelCurrentTransactionInternal() { mMonitor->AssertCurrentThreadOwns(); @@ -2135,91 +2107,20 @@ MessageChannel::CancelTransaction(int transaction) // tampered with (by us). If so, they don't reset the variable to the old // value. - IPC_LOG("CancelTransaction: xid=%d prios=%d", transaction, mPendingSendPriorities); + IPC_LOG("CancelInternal: current xid=%d", mCurrentTransaction); - if (mPendingSendPriorities & (1 << IPC::Message::PRIORITY_NORMAL)) { - // This isn't an assert so much as an intentional crash because we're in - // a situation that we don't know how to recover from: The child is - // awaiting a reply to a normal-priority sync message. The transaction - // that this message initiated has now been canceled. That could only - // happen if a CPOW raced with the sync message and was dispatched by - // the child while the child was awaiting the sync reply; at some point - // while dispatching the CPOW, the transaction was canceled. - // - // Notes: - // - // 1. We don't want to cancel the normal-priority sync message along - // with the CPOWs because the browser relies on these messages working - // reliably. - // - // 2. Ideally we would like to avoid dispatching CPOWs while awaiting a - // sync response. This isn't possible though. To avoid deadlock, the - // parent would have to dispatch the sync message while waiting for the - // CPOW response. However, it wouldn't have dispatched async messages at - // that time, so we would have a message ordering bug. Dispatching the - // async messages first causes other hard-to-handle situations (what if - // they send CPOWs?). - // - // 3. We would like to be able to cancel the CPOWs but not the sync - // message. However, that would leave both the parent and the child - // running code at the same time, all while the sync message is still - // outstanding. That can cause a problem where message replies are - // received out of order. - mListener->IntentionalCrash(); - } + MOZ_ASSERT(mCurrentTransaction); + mCurrentTransaction = 0; - // An unusual case: We timed out a transaction which the other side then - // cancelled. In this case we just leave the timedout state and try to - // forget this ever happened. - if (transaction == mTimedOutMessageSeqno) { - IPC_LOG("Cancelled timed out message %d", mTimedOutMessageSeqno); - EndTimeout(); - - // Normally mCurrentTransaction == 0 here. But it can be non-zero if: - // 1. Parent sends hi prio message H. - // 2. Parent times out H. - // 3. Child dispatches H and sends nested message H' (same transaction). - // 4. Parent dispatches H' and cancels. - MOZ_ASSERT_IF(mCurrentTransaction, mCurrentTransaction == transaction); - mCurrentTransaction = 0; - - // During a timeout Send should always fail. - MOZ_ASSERT(!mAwaitingSyncReply); - } else { - MOZ_ASSERT(mCurrentTransaction == transaction); - mCurrentTransaction = 0; - - mAwaitingSyncReply = false; - mAwaitingSyncReplyPriority = 0; - } - - DebugOnly foundSync = false; - for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) { - Message &msg = *it; - - // If there was a race between the parent and the child, then we may - // have a queued sync message. We want to drop this message from the - // queue since it will get cancelled along with the transaction being - // cancelled. We don't bother doing this for normal priority messages - // because the child is just going to crash in that case, and we want to - // avoid processing messages out of order in the short time before it - // crashes. - if (msg.is_sync() && msg.priority() != IPC::Message::PRIORITY_NORMAL) { - MOZ_ASSERT(!foundSync); - MOZ_ASSERT(msg.transaction_id() != transaction); - IPC_LOG("Removing msg from queue seqno=%d xid=%d", msg.seqno(), msg.transaction_id()); - foundSync = true; - it = mPending.erase(it); - continue; - } + mAwaitingSyncReply = false; + mAwaitingSyncReplyPriority = 0; + for (size_t i = 0; i < mPending.size(); i++) { // There may be messages in the queue that we expected to process from // ProcessPendingRequests. However, Send will no longer call that // function once it's been canceled. So we may need to process these // messages in the normal event loop instead. mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask)); - - it++; } // We could also zero out mDispatchingSyncMessage here. However, that would @@ -2233,17 +2134,10 @@ MessageChannel::CancelCurrentTransaction() { MonitorAutoLock lock(*mMonitor); if (mCurrentTransaction) { - if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_URGENT || - DispatchingAsyncMessagePriority() == IPC::Message::PRIORITY_URGENT) - { - mListener->IntentionalCrash(); - } - - IPC_LOG("Cancel requested: current xid=%d", mCurrentTransaction); - MOZ_ASSERT(DispatchingSyncMessage()); - CancelMessage *cancel = new CancelMessage(mCurrentTransaction); - CancelTransaction(mCurrentTransaction); + CancelMessage *cancel = new CancelMessage(); + cancel->set_transaction_id(mCurrentTransaction); mLink->SendMessage(cancel); + CancelCurrentTransactionInternal(); } } diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 1f2ec07f938c..72c25e12eae0 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -44,19 +44,6 @@ class RefCountedMonitor : public Monitor ~RefCountedMonitor() {} }; -enum class SyncSendError { - SendSuccess, - PreviousTimeout, - SendingCPOWWhileDispatchingSync, - SendingCPOWWhileDispatchingUrgent, - NotConnectedBeforeSend, - DisconnectedDuringSend, - CancelledBeforeSend, - CancelledAfterSend, - TimedOut, - ReplyError, -}; - class MessageChannel : HasResultCodes { friend class ProcessLink; @@ -145,13 +132,6 @@ class MessageChannel : HasResultCodes bool CanSend() const; - // If sending a sync message returns an error, this function gives a more - // descriptive error message. - SyncSendError LastSendError() const { - AssertWorkerThread(); - return mLastSendError; - } - // Currently only for debugging purposes, doesn't aquire mMonitor. ChannelState GetChannelState__TotallyRacy() const { return mChannelState; @@ -270,7 +250,7 @@ class MessageChannel : HasResultCodes bool InterruptEventOccurred(); bool HasPendingEvents(); - void ProcessPendingRequests(int seqno, int transaction); + void ProcessPendingRequests(int transaction, int prio); bool ProcessPendingRequest(const Message &aUrgent); void MaybeUndeferIncall(); @@ -308,8 +288,7 @@ class MessageChannel : HasResultCodes bool ShouldContinueFromTimeout(); - void EndTimeout(); - void CancelTransaction(int transaction); + void CancelCurrentTransactionInternal(); // The "remote view of stack depth" can be different than the // actual stack depth when there are out-of-turn replies. When we @@ -447,7 +426,7 @@ class MessageChannel : HasResultCodes // Tell the IO thread to close the channel and wait for it to ACK. void SynchronouslyClose(); - bool WasTransactionCanceled(int transaction); + bool WasTransactionCanceled(int transaction, int prio); bool ShouldDeferMessage(const Message& aMsg); void OnMessageReceivedFromLink(const Message& aMsg); void OnChannelErrorFromLink(); @@ -542,9 +521,6 @@ class MessageChannel : HasResultCodes static bool sIsPumpingMessages; - // If ::Send returns false, this gives a more descriptive error. - SyncSendError mLastSendError; - template class AutoSetValue { public: @@ -600,13 +576,6 @@ class MessageChannel : HasResultCodes // The current transaction ID. int32_t mCurrentTransaction; - // This field describes the priorities of the sync Send calls that are - // currently on stack. If a Send call for a message with priority P is on - // the C stack, then mPendingSendPriorities & (1 << P) will be - // non-zero. Note that cancelled Send calls are not removed from this - // bitfield (until they return). - int mPendingSendPriorities; - class AutoEnterTransaction { public: diff --git a/ipc/glue/MessageLink.h b/ipc/glue/MessageLink.h index 0b382bcfa0ac..06632467449c 100644 --- a/ipc/glue/MessageLink.h +++ b/ipc/glue/MessageLink.h @@ -76,11 +76,6 @@ class MessageListener return false; } - // WARNING: This function is called with the MessageChannel monitor held. - virtual void IntentionalCrash() { - MOZ_CRASH("Intentional IPDL crash"); - } - virtual void OnEnteredCxxStack() { NS_RUNTIMEABORT("default impl shouldn't be invoked"); } diff --git a/xpcom/base/Logging.cpp b/xpcom/base/Logging.cpp index 2679b9378a06..c4c752a0e17a 100644 --- a/xpcom/base/Logging.cpp +++ b/xpcom/base/Logging.cpp @@ -87,7 +87,6 @@ public: , mModules(kInitialModuleCount) , mOutFile(nullptr) , mAddTimestamp(false) - , mIsSync(false) { } @@ -104,24 +103,20 @@ public: { bool shouldAppend = false; bool addTimestamp = false; - bool isSync = false; const char* modules = PR_GetEnv("NSPR_LOG_MODULES"); NSPRLogModulesParser(modules, - [&shouldAppend, &addTimestamp, &isSync] + [&shouldAppend, &addTimestamp] (const char* aName, LogLevel aLevel) mutable { if (strcmp(aName, "append") == 0) { shouldAppend = true; } else if (strcmp(aName, "timestamp") == 0) { addTimestamp = true; - } else if (strcmp(aName, "sync") == 0) { - isSync = true; } else { LogModule::Get(aName)->SetLevel(aLevel); } }); mAddTimestamp = addTimestamp; - mIsSync = isSync; const char* logFile = PR_GetEnv("NSPR_LOG_FILE"); if (logFile && logFile[0]) { @@ -193,10 +188,6 @@ public: aName, buffToWrite, newline); } - if (mIsSync) { - fflush(out); - } - if (buffToWrite != buff) { PR_smprintf_free(buffToWrite); } @@ -207,7 +198,6 @@ private: nsClassHashtable mModules; ScopedCloseFile mOutFile; bool mAddTimestamp; - bool mIsSync; }; StaticAutoPtr sLogModuleManager;