- Timestamp:
- Apr 15, 2016 7:25:46 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp
r57846 r60525 218 218 * This is shadowed by INTNETMACTABENTRY::fActive. */ 219 219 bool fActive; 220 /** Whether someone is currently in the destructor or has indicated that 221 * the end is nigh by means of IntNetR0IfAbortWait. */ 222 bool volatile fDestroying; 220 /** Whether someone has indicated that the end is nigh by means of IntNetR0IfAbortWait. */ 221 bool volatile fNoMoreWaits; 223 222 /** The flags specified when opening this interface. */ 224 223 uint32_t fOpenFlags; … … 240 239 RTSEMEVENT volatile hRecvEvent; 241 240 /** Number of threads sleeping on the event semaphore. */ 242 uint32_t 241 uint32_t volatile cSleepers; 243 242 /** The interface handle. 244 243 * When this is INTNET_HANDLE_INVALID a sleeper which is waking up 245 244 * should return with the appropriate error condition. */ 246 245 INTNETIFHANDLE volatile hIf; 246 /** The native handle of the destructor thread. This is NIL_RTNATIVETHREAD when 247 * the object is valid and set when intnetR0IfDestruct is in progress. This is 248 * used to cover an unlikely (impossible?) race between SUPDRVSESSION cleanup 249 * and lingering threads waiting for recv or similar. */ 250 RTNATIVETHREAD volatile hDestructorThread; 247 251 /** Pointer to the network this interface is connected to. 248 252 * This is protected by the INTNET::hMtxCreateOpenDestroy. */ … … 771 775 DECLINLINE(int) intnetR0IfRetain(PINTNETIF pIf, PSUPDRVSESSION pSession) 772 776 { 777 Assert(((PINTNETIF)pIf->pvObj)->hDestructorThread == NIL_RTNATIVETHREAD); 778 773 779 int rc = SUPR0ObjAddRefEx(pIf->pvObj, pSession, true /* fNoBlocking */); 774 780 AssertRCReturn(rc, rc); 781 775 782 return VINF_SUCCESS; 776 783 } … … 787 794 DECLINLINE(bool) intnetR0IfRelease(PINTNETIF pIf, PSUPDRVSESSION pSession) 788 795 { 796 Assert(((PINTNETIF)pIf->pvObj)->hDestructorThread == NIL_RTNATIVETHREAD); 797 789 798 int rc = SUPR0ObjRelease(pIf->pvObj, pSession); 790 799 AssertRC(rc); 800 791 801 return rc == VINF_OBJECT_DESTROYED; 792 802 } … … 809 819 NOREF(pvUser); 810 820 NOREF(hHandleTable); 811 PINTNETIF pIf = (PINTNETIF)pvObj; 812 if (pIf->hIf != INTNET_HANDLE_INVALID) /* Don't try retain it if called from intnetR0IfDestruct. */ 821 822 PINTNETIF pIf = (PINTNETIF)pvObj; 823 RTNATIVETHREAD hDtorThrd; 824 ASMAtomicUoReadHandle(&pIf->hDestructorThread, &hDtorThrd); 825 if (hDtorThrd == NIL_RTNATIVETHREAD) 813 826 return intnetR0IfRetain(pIf, (PSUPDRVSESSION)pvCtx); 814 return VINF_SUCCESS; 827 828 /* Allow intnetR0IfDestruct to call RTHandleTableFreeWithCtx to free 829 the handle, but not even think about retaining a referenceas we don't 830 want to confuse SUPDrv and risk having the destructor called twice. */ 831 if (hDtorThrd == RTThreadNativeSelf()) 832 return VINF_SUCCESS; 833 834 return VERR_SEM_DESTROYED; 815 835 } 816 836 … … 4618 4638 } 4619 4639 4620 const INTNETIFHANDLE hIfSelf = pIf->hIf; 4621 const RTSEMEVENT hRecvEvent = pIf->hRecvEvent; 4622 const bool fDestroying = ASMAtomicReadBool(&pIf->fDestroying); 4623 if ( hIfSelf != hIf /* paranoia */ 4624 || hRecvEvent == NIL_RTSEMEVENT 4625 || fDestroying 4626 ) 4627 { 4640 const RTSEMEVENT hRecvEvent = pIf->hRecvEvent; 4641 const bool fNoMoreWaits = ASMAtomicUoReadBool(&pIf->fNoMoreWaits); 4642 RTNATIVETHREAD hDtorThrd; 4643 ASMAtomicReadHandle(&pIf->hDestructorThread, &hDtorThrd); 4644 if (hDtorThrd != NIL_RTNATIVETHREAD) 4645 { 4646 /* See IntNetR0IfAbortWait for an explanation of hDestructorThread. */ 4628 4647 Log(("IntNetR0IfWait: returns VERR_SEM_DESTROYED\n")); 4629 4648 return VERR_SEM_DESTROYED; 4630 4649 } 4631 4650 4632 /* 4633 * It is tempting to check if there is data to be read here, 4634 * but the problem with such an approach is that it will cause 4635 * one unnecessary supervisor->user->supervisor trip. There is 4636 * already a slight risk for such, so no need to increase it. 4637 */ 4638 4639 /* 4640 * Increment the number of waiters before starting the wait. 4641 * Upon wakeup we must assert reality, checking that we're not 4642 * already destroyed or in the process of being destroyed. This 4643 * code must be aligned with the waiting code in intnetR0IfDestruct. 4644 */ 4645 ASMAtomicIncU32(&pIf->cSleepers); 4646 int rc = RTSemEventWaitNoResume(hRecvEvent, cMillies); 4647 if (pIf->hRecvEvent == hRecvEvent) 4648 { 4649 ASMAtomicDecU32(&pIf->cSleepers); 4650 if (!pIf->fDestroying) 4651 /* Check whether further waits have been barred by IntNetR0IfAbortWait. */ 4652 int rc; 4653 if ( !fNoMoreWaits 4654 && hRecvEvent != NIL_RTSEMEVENT) 4655 { 4656 /* 4657 * It is tempting to check if there is data to be read here, 4658 * but the problem with such an approach is that it will cause 4659 * one unnecessary supervisor->user->supervisor trip. There is 4660 * already a slight risk for such, so no need to increase it. 4661 */ 4662 4663 /* 4664 * Increment the number of waiters before starting the wait. 4665 * Upon wakeup we must assert reality, checking that we're not 4666 * already destroyed or in the process of being destroyed. This 4667 * code must be aligned with the waiting code in intnetR0IfDestruct. 4668 */ 4669 ASMAtomicIncU32(&pIf->cSleepers); 4670 rc = RTSemEventWaitNoResume(hRecvEvent, cMillies); 4671 if (pIf->hRecvEvent == hRecvEvent) 4651 4672 { 4652 if (intnetR0IfRelease(pIf, pSession)) 4673 ASMAtomicDecU32(&pIf->cSleepers); 4674 ASMAtomicReadHandle(&pIf->hDestructorThread, &hDtorThrd); 4675 if (hDtorThrd == NIL_RTNATIVETHREAD) 4676 { 4677 if (intnetR0IfRelease(pIf, pSession)) 4678 rc = VERR_SEM_DESTROYED; 4679 } 4680 else 4653 4681 rc = VERR_SEM_DESTROYED; 4654 4682 } … … 4657 4685 } 4658 4686 else 4687 { 4659 4688 rc = VERR_SEM_DESTROYED; 4689 intnetR0IfRelease(pIf, pSession); 4690 } 4691 4660 4692 Log4(("IntNetR0IfWait: returns %Rrc\n", rc)); 4661 4693 return rc; … … 4704 4736 } 4705 4737 4706 const INTNETIFHANDLE hIfSelf = pIf->hIf; 4707 const RTSEMEVENT hRecvEvent = pIf->hRecvEvent; 4708 const bool fDestroying = ASMAtomicReadBool(&pIf->fDestroying); 4709 if ( hIfSelf != hIf /* paranoia */ 4710 || hRecvEvent == NIL_RTSEMEVENT 4711 || fDestroying 4712 ) 4713 { 4738 const RTSEMEVENT hRecvEvent = pIf->hRecvEvent; 4739 RTNATIVETHREAD hDtorThrd; 4740 ASMAtomicReadHandle(&pIf->hDestructorThread, &hDtorThrd); 4741 if (hDtorThrd != NIL_RTNATIVETHREAD) 4742 { 4743 /* This can only happen if we for some reason race SUPDRVSESSION cleanup, 4744 i.e. the object count is set to zero without yet having removed it from 4745 the object table, so we got a spurious "reference". We must drop that 4746 reference and let the destructor get on with its work. (Not entirely sure 4747 if this is practically possible on any of the platforms, i.e. whether it's 4748 we can actually close a SUPDrv handle/descriptor with active threads still 4749 in NtDeviceIoControlFile/ioctl, but better safe than sorry.) */ 4714 4750 Log(("IntNetR0IfAbortWait: returns VERR_SEM_DESTROYED\n")); 4715 4751 return VERR_SEM_DESTROYED; 4716 4752 } 4717 4753 4718 /* 4719 * Set fDestroying if requested to do so and then wake up all the sleeping 4720 * threads (usually just one). We leave the semaphore in the signalled 4721 * state so the next caller will return immediately. 4722 */ 4723 if (fNoMoreWaits) 4724 ASMAtomicWriteBool(&pIf->fDestroying, true); 4725 4726 uint32_t cSleepers = ASMAtomicReadU32(&pIf->cSleepers) + 1; 4727 while (cSleepers-- > 0) 4728 { 4729 int rc = RTSemEventSignal(pIf->hRecvEvent); 4730 AssertRC(rc); 4731 } 4754 /* a bit of paranoia */ 4755 int rc = VINF_SUCCESS; 4756 if (hRecvEvent != NIL_RTSEMEVENT) 4757 { 4758 /* 4759 * Set fNoMoreWaits if requested to do so and then wake up all the sleeping 4760 * threads (usually just one). We leave the semaphore in the signalled 4761 * state so the next caller will return immediately. 4762 */ 4763 if (fNoMoreWaits) 4764 ASMAtomicWriteBool(&pIf->fNoMoreWaits, true); 4765 4766 uint32_t cSleepers = ASMAtomicReadU32(&pIf->cSleepers) + 1; 4767 while (cSleepers-- > 0) 4768 { 4769 int rc2 = RTSemEventSignal(pIf->hRecvEvent); 4770 AssertRC(rc2); 4771 } 4772 } 4773 else 4774 rc = VERR_SEM_DESTROYED; 4775 4776 intnetR0IfRelease(pIf, pSession); 4732 4777 4733 4778 Log4(("IntNetR0IfWait: returns %Rrc\n", VINF_SUCCESS)); … … 4831 4876 4832 4877 /* 4878 * For paranoid reasons we must now mark the interface as destroyed. 4879 * This is so that any waiting threads can take evasive action (kind 4880 * of theoretical case), and we can reject everyone else referencing 4881 * the object via the handle table before we get around to removing it. 4882 */ 4883 ASMAtomicWriteHandle(&pIf->hDestructorThread, RTThreadNativeSelf()); 4884 4885 /* 4833 4886 * We grab the INTNET create/open/destroy semaphore to make sure nobody is 4834 * adding or removing interface while we're in here. For paranoid reasons 4835 * we also mark the interface as destroyed here so any waiting threads can 4836 * take evasive action (theoretical case). 4887 * adding or removing interfaces while we're in here. 4837 4888 */ 4838 4889 RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT); 4839 ASMAtomicWriteBool(&pIf->fDestroying, true);4840 4890 4841 4891 /* … … 4921 4971 4922 4972 /* 4923 * Wakeup anyone waiting on this interface. 4973 * Wakeup anyone waiting on this interface. (Kind of unlikely, but perhaps 4974 * not quite impossible.) 4924 4975 * 4925 4976 * We *must* make sure they have woken up properly and realized … … 5045 5096 //pIf->fPromiscuousReal = false; 5046 5097 //pIf->fActive = false; 5047 //pIf->f Destroying= false;5098 //pIf->fNoMoreWaits = false; 5048 5099 pIf->fOpenFlags = fFlags; 5049 5100 //pIf->cYields = 0; … … 5055 5106 //pIf->cSleepers = 0; 5056 5107 pIf->hIf = INTNET_HANDLE_INVALID; 5108 pIf->hDestructorThread = NIL_RTNATIVETHREAD; 5057 5109 pIf->pNetwork = pNetwork; 5058 5110 pIf->pSession = pSession;
Note:
See TracChangeset
for help on using the changeset viewer.