VirtualBox

Changeset 3276 in vbox


Ignore:
Timestamp:
Jun 25, 2007 2:36:15 PM (17 years ago)
Author:
vboxsync
Message:

XPCOM/IPC/DConnect: Restored and fixed r21798.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp

    r3058 r3276  
    234234    count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
    235235    if (0 == count) {
     236      NS_PRECONDITION(PRInt32(mRefCntIPC) == 0, "non-zero IPC refcnt");
    236237      mRefCnt = 1; /* stabilize */
     238      delete this;
     239      return 0;
     240    }
     241    return count;
     242  }
     243
     244  // this gets called after calling AddRef() on an instance passed to the
     245  // client over IPC in order to have a count of IPC client-related references
     246  // separately from the overall reference count
     247  NS_IMETHODIMP_(nsrefcnt) AddRefIPC(void)
     248  {
     249    NS_PRECONDITION(PRInt32(mRefCntIPC) >= 0, "illegal refcnt");
     250    nsrefcnt count = PR_AtomicIncrement((PRInt32*)&mRefCntIPC);
     251    return count;
     252  }
     253
     254  // this gets called before calling Release() when DCON_OP_RELEASE is
     255  // received from the IPC client and in other cases to balance AddRefIPC()
     256  NS_IMETHODIMP_(nsrefcnt) ReleaseIPC(PRBool locked = PR_FALSE)
     257  {
     258    NS_PRECONDITION(0 != mRefCntIPC, "dup release");
     259    nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCntIPC);
     260    if (0 == count) {
     261      // If the last IPC reference is releaed, remove this instance from the map.
    237262      // ipcDConnectService is guaranteed to still exist here
    238263      // (DConnectInstance lifetime is bound to ipcDConnectService)
    239264      nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
    240265      if (dConnect)
    241         dConnect->DeleteInstance(this);
     266        dConnect->DeleteInstance(this, locked);
    242267      else
    243268        NS_NOTREACHED("ipcDConnectService has gone before DConnectInstance");
    244       delete this;
    245       return 0;
    246269    }
    247270    return count;
     
    250273private:
    251274  nsAutoRefCnt               mRefCnt;
     275  nsAutoRefCnt               mRefCntIPC;
    252276  PRUint32                   mPeer;  // peer process "owning" this instance
    253277  nsCOMPtr<nsIInterfaceInfo> mIInfo;
     
    259283{
    260284  for (PRInt32 i=0; i<wrappers.Count(); ++i)
     285  {
     286    ((DConnectInstance *) wrappers[i])->ReleaseIPC();
    261287    ((DConnectInstance *) wrappers[i])->Release();
     288  }
    262289}
    263290
     
    10981125        wrapper->AddRef();
    10991126      }
     1127
     1128      // increase the second, IPC-only, reference counter (mandatory before
     1129      // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove
     1130      // the wrapper from the instance map on failure)
     1131      wrapper->AddRefIPC();
    11001132       
    11011133      if (!wrappers.AppendElement(wrapper))
    11021134      {
     1135        wrapper->ReleaseIPC();
    11031136        wrapper->Release();
    11041137        return NS_ERROR_OUT_OF_MEMORY;
     
    13651398          wrapper->AddRef();
    13661399        }
     1400
     1401        // increase the second, IPC-only, reference counter (mandatory before
     1402        // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove
     1403        // the wrapper from the instance map on failure)
     1404        wrapper->AddRefIPC();
    13671405       
    13681406        if (!wrappers.AppendElement(wrapper))
    13691407        {
     1408          wrapper->ReleaseIPC();
    13701409          wrapper->Release();
    13711410          return NS_ERROR_OUT_OF_MEMORY;
     
    13741413        // wrapper remains referenced when passing it to the client
    13751414        // (will be released upon DCON_OP_RELEASE)
    1376      
     1415
    13771416        // send address of the instance wrapper, and set the low bit
    13781417        // to indicate that this is an instance wrapper.
     
    16461685  }
    16471686 
    1648   if (0 == count) {
     1687  if (0 == count)
     1688  {
    16491689    mRefCnt = 1; /* stabilize */
    16501690    delete this;
     
    16971737 
    16981738  // else, we need to query the peer object
    1699   LOG(("calling QueryInterface on peer object\n"));
     1739
     1740#ifdef IPC_LOGGING
     1741  {
     1742    nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
     1743    if (dConnect)
     1744    {
     1745      const char *name;
     1746      nsCOMPtr <nsIInterfaceInfo> iinfo;
     1747      GetInterfaceInfo(getter_AddRefs(iinfo));
     1748      iinfo->GetNameShared(&name);
     1749      const char *nameQ;
     1750      nsCOMPtr <nsIInterfaceInfo> iinfoQ;
     1751      dConnect->GetInterfaceInfo(aIID, getter_AddRefs(iinfoQ));
     1752      iinfoQ->GetNameShared(&nameQ);
     1753      LOG(("calling QueryInterface {%s} on peer object "
     1754           "(stub=%p, instance=%p {%s})\n",
     1755           nameQ, this, mInstance, name));
     1756    }
     1757  }
     1758#endif
    17001759
    17011760  DConnectSetupQueryInterface msg;
     
    26742733  if (args && args->clientID == aData->Peer())
    26752734  {
    2676     // ignore the reference counter: the client is officially dead
    2677     args->that->DeleteInstance(aData, PR_TRUE /* locked */);
    2678     // collect the instance for future destruction
     2735    nsrefcnt countIPC = aData->ReleaseIPC(PR_TRUE /* locked */);
     2736
     2737    LOG(("ipcDConnectService::PruneInstanceMapForPeer: "
     2738         "instance=%p: %d IPC refs to release\n",
     2739         aData, countIPC + 1));
     2740
     2741    // release all IPC instances of the "officially dead" client (see
     2742    // #OnRelease() to understand why it must be done under the lock). Note
     2743    // that due to true multithreading, late OnRelease() requests may still
     2744    // happen on other worker threads *after* OnClientStateChange() has been
     2745    // called, but it's OK because the instance will be removed from the map
     2746    // by the below code alreay and won't be deleted for the second time.
     2747    while (countIPC)
     2748    {
     2749      countIPC = aData->ReleaseIPC(PR_TRUE /* locked */);
     2750      aData->Release();
     2751    }
     2752
     2753    // collect the instance for the last release
     2754    // (we'll do it later outside the lock)
    26792755    if (!args->wrappers.AppendElement(aData))
    26802756    {
    26812757      NS_NOTREACHED("Not enough memory");
    26822758      // bad but what to do
    2683       delete aData;
     2759      aData->Release();
    26842760    }
    26852761  }
     
    27172793      }
    27182794
    2719       // destruct all instances outside the lock because it will release
    2720       // the real objects which may need to make asynchronous use our service
     2795      LOG(("ipcDConnectService::OnClientStateChange: "
     2796           "%d lost instances\n", wrappers.Count()));
     2797
     2798      // release all pending references left after PruneInstanceMapForPeer().
     2799      // this may call wrapper destructors so it's important to do that
     2800      // outside the lock because destructors will release the real objects
     2801      // which may need to make asynchronous use our service
    27212802      for (PRInt32 i = 0; i < wrappers.Count(); ++i)
    2722         delete ((DConnectInstance *) wrappers[i]);
     2803        ((DConnectInstance *) wrappers[i])->Release();
    27232804    }
    27242805  }
     
    28652946            // reference the newly created wrapper
    28662947            wrapper->AddRef();
    2867 
    2868             if (!wrappers.AppendElement(wrapper))
    2869             {
    2870               NS_RELEASE(wrapper);
    2871               rv = NS_ERROR_OUT_OF_MEMORY;
    2872             }
    28732948          }
     2949        }
     2950      }
     2951
     2952      if (wrapper)
     2953      {
     2954        // increase the second, IPC-only, reference counter (mandatory before
     2955        // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove
     2956        // the wrapper from the instance map on failure)
     2957        wrapper->AddRefIPC();
     2958
     2959        if (!wrappers.AppendElement(wrapper))
     2960        {
     2961          wrapper->ReleaseIPC();
     2962          wrapper->Release();
     2963          rv = NS_ERROR_OUT_OF_MEMORY;
    28742964        }
    28752965      }
     
    29473037  if (mInstanceSet.Contains(wrapper))
    29483038  {
    2949     nsrefcnt count = wrapper->AddRef();
    2950     count = wrapper->Release();
    2951     if (count == 1)
    2952     {
    2953       // we are the last one who holds a (fake) reference, remove the
    2954       // instace from instance maps while still under the lock
    2955       DeleteInstance(wrapper, PR_TRUE /* locked */);
    2956       // leave the lock before calling the destructor because it will release
    2957       // the real object which may need to make asynchronous use our service
    2958       lock.unlock();
    2959       delete wrapper;
    2960     }
     3039    // release the IPC reference from under the lock to ensure atomicity of
     3040    // the "check + possible delete" sequence ("delete" is remove this wrapper
     3041    // from the instance map when the IPC reference counter drops to zero)
     3042    wrapper->ReleaseIPC(PR_TRUE /* locked */);
     3043    // leave the lock before Release() because it may call the destructor
     3044    // which will release the real object which may need to make asynchronous
     3045    // use our service
     3046    lock.unlock();
     3047    wrapper->Release();
    29613048  }
    29623049  else
    29633050  {
    29643051    // it is possible that the client disconnection event handler has released
    2965     // all client instances before the RELEASE message sent by the client gets
    2966     // processed here. Just give a warning
    2967     LOG(("ipcDConnectService::OnRelease: WARNING: instance wrapper not found"));
     3052    // all client instances before the DCON_OP_RELEASE message sent by the
     3053    // client gets processed here (because of true multithreading). Just log
     3054    // a debug warning
     3055    LOG(("ipcDConnectService::OnRelease: WARNING: "
     3056         "instance wrapper %p not found", wrapper));
    29683057  }
    29693058}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette