Changeset 103488 in vbox
- Timestamp:
- Feb 21, 2024 10:55:12 AM (9 months ago)
- Location:
- trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp
r103476 r103488 64 64 #endif /* VBOX */ 65 65 66 #if defined(DCONNECT_MULTITHREADED)67 68 #if !defined(DCONNECT_WITH_IPRT_REQ_POOL)69 #include "nsIRunnable.h"70 #endif71 72 66 #if defined(DEBUG) && !defined(DCONNECT_STATS) 73 67 #define DCONNECT_STATS … … 76 70 #if defined(DCONNECT_STATS) 77 71 #include <stdio.h> 78 #endif79 80 72 #endif 81 73 … … 2881 2873 //----------------------------------------------------------------------------- 2882 2874 2883 #if defined(DCONNECT_MULTITHREADED) && !defined(DCONNECT_WITH_IPRT_REQ_POOL)2884 2885 class DConnectWorker : public nsIRunnable2886 {2887 public:2888 // no reference counting2889 NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }2890 NS_IMETHOD_(nsrefcnt) Release() { return 1; }2891 NS_IMETHOD QueryInterface(const nsIID &aIID, void **aInstancePtr);2892 2893 NS_DECL_NSIRUNNABLE2894 2895 DConnectWorker(ipcDConnectService *aDConnect) : mDConnect (aDConnect), mIsRunnable (PR_FALSE) {}2896 NS_HIDDEN_(nsresult) Init();2897 NS_HIDDEN_(void) Join()2898 {2899 int rcThread;2900 int vrc = RTThreadWait(mThread, RT_INDEFINITE_WAIT, &rcThread);2901 AssertRC(vrc); RT_NOREF(vrc);2902 AssertRC(rcThread);2903 };2904 NS_HIDDEN_(bool) IsRunning() { return mIsRunnable; };2905 2906 private:2907 2908 static DECLCALLBACK(int) dconnectWorkerRun(RTTHREAD hSelf, void *pvUser);2909 2910 RTTHREAD mThread;2911 ipcDConnectService *mDConnect;2912 2913 // Indicate if thread might be quickly joined on shutdown.2914 volatile bool mIsRunnable;2915 };2916 2917 NS_IMPL_QUERY_INTERFACE1(DConnectWorker, nsIRunnable)2918 2919 /*static*/2920 DECLCALLBACK(int) DConnectWorker::dconnectWorkerRun(RTTHREAD hSelf, void *pvUser)2921 {2922 DConnectWorker *pThis = (DConnectWorker *)pvUser;2923 pThis->Run();2924 return VINF_SUCCESS;2925 }2926 2927 2928 nsresult2929 DConnectWorker::Init()2930 {2931 int vrc = RTThreadCreate(&mThread, dconnectWorkerRun, this, 0 /*cbStack*/,2932 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "DConWrk");2933 if (RT_FAILURE(vrc))2934 return NS_ERROR_FAILURE;2935 2936 return NS_OK;2937 }2938 2939 NS_IMETHODIMP2940 DConnectWorker::Run()2941 {2942 Log(("DConnect Worker thread started.\n"));2943 2944 mIsRunnable = PR_TRUE;2945 2946 nsAutoMonitor mon(mDConnect->mPendingMon);2947 2948 while (!mDConnect->mDisconnected)2949 {2950 DConnectRequest *request = mDConnect->mPendingQ.First();2951 if (!request)2952 {2953 mDConnect->mWaitingWorkers++;2954 {2955 // Note: we attempt to enter mWaitingWorkersMon from under mPendingMon2956 // here, but it should be safe because it's the only place where it2957 // happens. We could exit mPendingMon first, but we need to wait on it2958 // shorltly afterwards, which in turn will require us to enter it again2959 // just to exit immediately and start waiting. This seems to me a bit2960 // stupid (exit->enter->exit->wait).2961 nsAutoMonitor workersMon(mDConnect->mWaitingWorkersMon);2962 workersMon.NotifyAll();2963 }2964 2965 nsresult rv = mon.Wait();2966 mDConnect->mWaitingWorkers--;2967 2968 if (NS_FAILED(rv))2969 break;2970 }2971 else2972 {2973 Log(("DConnect Worker thread got request.\n"));2974 2975 // remove the request from the queue2976 mDConnect->mPendingQ.RemoveFirst();2977 2978 PRBool pendingQEmpty = mDConnect->mPendingQ.IsEmpty();2979 mon.Exit();2980 2981 if (pendingQEmpty)2982 {2983 nsAutoMonitor workersMon(mDConnect->mWaitingWorkersMon);2984 workersMon.NotifyAll();2985 }2986 2987 // request is processed outside the queue monitor2988 mDConnect->OnIncomingRequest(request->peer, request->op, request->opLen);2989 delete request;2990 2991 mon.Enter();2992 }2993 }2994 2995 mIsRunnable = PR_FALSE;2996 2997 Log(("DConnect Worker thread stopped.\n"));2998 return NS_OK;2999 }3000 3001 // called only on DConnect message thread3002 nsresult3003 ipcDConnectService::CreateWorker()3004 {3005 DConnectWorker *worker = new DConnectWorker(this);3006 if (!worker)3007 return NS_ERROR_OUT_OF_MEMORY;3008 nsresult rv = worker->Init();3009 if (NS_SUCCEEDED(rv))3010 {3011 nsAutoLock lock(mLock);3012 /* tracking an illegal join in Shutdown. */3013 NS_ASSERTION(!mDisconnected, "CreateWorker racing Shutdown");3014 if (!mWorkers.AppendElement(worker))3015 rv = NS_ERROR_OUT_OF_MEMORY;3016 }3017 if (NS_FAILED(rv))3018 delete worker;3019 return rv;3020 }3021 3022 #endif // defined(DCONNECT_MULTITHREADED) && !defined(DCONNECT_WITH_IPRT_REQ_POOL)3023 3024 //-----------------------------------------------------------------------------3025 3026 2875 ipcDConnectService::ipcDConnectService() 3027 2876 : mLock(NIL_RTSEMFASTMUTEX) … … 3029 2878 , mDisconnected(PR_TRUE) 3030 2879 , mStubQILock(NIL_RTSEMFASTMUTEX) 3031 #if defined(DCONNECT_WITH_IPRT_REQ_POOL)3032 2880 , mhReqPool(NIL_RTREQPOOL) 3033 #endif3034 2881 { 3035 2882 } … … 3068 2915 RTSemFastMutexDestroy(mLock); 3069 2916 3070 #if defined(DCONNECT_WITH_IPRT_REQ_POOL)3071 2917 RTReqPoolRelease(mhReqPool); 3072 2918 mhReqPool = NIL_RTREQPOOL; 3073 #endif3074 2919 } 3075 2920 … … 3115 2960 return NS_ERROR_OUT_OF_MEMORY; 3116 2961 3117 #if defined(DCONNECT_MULTITHREADED)3118 # if defined(DCONNECT_WITH_IPRT_REQ_POOL)3119 2962 vrc = RTReqPoolCreate(1024 /*cMaxThreads*/, 10*RT_MS_1SEC /*cMsMinIdle*/, 3120 2963 8 /*cThreadsPushBackThreshold */, RT_MS_1SEC /* cMsMaxPushBack */, … … 3127 2970 3128 2971 mDisconnected = PR_FALSE; 3129 3130 # else3131 3132 mPendingMon = nsAutoMonitor::NewMonitor("DConnect pendingQ monitor");3133 if (!mPendingMon)3134 return NS_ERROR_OUT_OF_MEMORY;3135 3136 mWaitingWorkers = 0;3137 3138 mWaitingWorkersMon = nsAutoMonitor::NewMonitor("DConnect waiting workers monitor");3139 if (!mWaitingWorkersMon)3140 return NS_ERROR_OUT_OF_MEMORY;3141 3142 /* The DConnectWorker::Run method checks the ipcDConnectService::mDisconnected.3143 * So mDisconnect must be set here to avoid an immediate exit of the worker thread.3144 */3145 mDisconnected = PR_FALSE;3146 3147 // create a single worker thread3148 rv = CreateWorker();3149 if (NS_FAILED(rv))3150 {3151 mDisconnected = PR_TRUE;3152 return rv;3153 }3154 3155 # endif3156 #else3157 3158 mDisconnected = PR_FALSE;3159 3160 #endif3161 3162 2972 mInstance = this; 3163 2973 … … 3176 2986 } 3177 2987 3178 #if defined(DCONNECT_MULTITHREADED) 3179 # if defined(DCONNECT_WITH_IPRT_REQ_POOL) 3180 3181 # if defined(DCONNECT_STATS) 2988 #if defined(DCONNECT_STATS) 3182 2989 fprintf(stderr, "ipcDConnectService Stats\n"); 3183 2990 fprintf(stderr, … … 3192 2999 RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_NS_AVERAGE_REQ_QUEUED) 3193 3000 ); 3194 # 3001 #endif 3195 3002 3196 3003 RTReqPoolRelease(mhReqPool); 3197 3004 mhReqPool = NIL_RTREQPOOL; 3198 3199 # else3200 3201 {3202 // remove all pending messages and wake up all workers.3203 // mDisconnected is true here and they will terminate execution after3204 // processing the last request.3205 nsAutoMonitor mon(mPendingMon);3206 mPendingQ.DeleteAll();3207 mon.NotifyAll();3208 }3209 3210 #if defined(DCONNECT_STATS)3211 fprintf(stderr, "ipcDConnectService Stats\n");3212 fprintf(stderr, " => number of worker threads: %d\n", mWorkers.Count());3213 Log(("ipcDConnectService Stats\n"));3214 Log((" => number of worker threads: %d\n", mWorkers.Count()));3215 #endif3216 3217 3218 // Iterate over currently running worker threads3219 // during VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS, join() those who3220 // exited a working loop and abandon ones which have not3221 // managed to do that when timeout occurred.3222 Log(("Worker threads: %d\n", mWorkers.Count()));3223 uint64_t tsStart = RTTimeMilliTS();3224 while ((tsStart + VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS ) > RTTimeMilliTS() && mWorkers.Count() > 0)3225 {3226 // Some array elements might be deleted while iterating. Going from the last3227 // to the first array element (intentionally) in order to do not conflict with3228 // array indexing once element is deleted.3229 for (int i = mWorkers.Count() - 1; i >= 0; i--)3230 {3231 DConnectWorker *worker = NS_STATIC_CAST(DConnectWorker *, mWorkers[i]);3232 if (worker->IsRunning() == PR_FALSE)3233 {3234 Log(("Worker %p joined.\n", worker));3235 worker->Join();3236 delete worker;3237 mWorkers.RemoveElementAt(i);3238 }3239 }3240 3241 /* Double-ckeck if we already allowed to quit. */3242 if ((tsStart + VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS ) < RTTimeMilliTS() || mWorkers.Count() == 0)3243 break;3244 3245 // Relax a bit before the next round.3246 RTThreadSleep(10);3247 }3248 3249 Log(("There are %d thread(s) left.\n", mWorkers.Count()));3250 3251 // If there are some running threads left, terminate the process.3252 if (mWorkers.Count() > 0)3253 exit(1);3254 3255 3256 nsAutoMonitor::DestroyMonitor(mWaitingWorkersMon);3257 nsAutoMonitor::DestroyMonitor(mPendingMon);3258 3259 # endif3260 #endif3261 3005 3262 3006 // make sure we have released all instances … … 3529 3273 aSenderID, op->opcode_major, op->request_index)); 3530 3274 3531 #if defined(DCONNECT_MULTITHREADED)3532 # if defined(DCONNECT_WITH_IPRT_REQ_POOL)3533 3534 3275 void *pvDataDup = RTMemDup(aData, aDataLen); 3535 3276 if (RT_UNLIKELY(!pvDataDup)) … … 3540 3281 return NS_ERROR_FAILURE; 3541 3282 3542 # else3543 3544 nsAutoMonitor mon(mPendingMon);3545 mPendingQ.Append(new DConnectRequest(aSenderID, op, aDataLen));3546 // notify a worker3547 mon.Notify();3548 mon.Exit();3549 3550 // Yield the cpu so a worker can get a chance to start working without too much fuss.3551 RTThreadYield();3552 mon.Enter();3553 // examine the queue3554 if (mPendingQ.Count() > mWaitingWorkers)3555 {3556 // wait a little while to let the workers empty the queue.3557 mon.Exit();3558 {3559 nsAutoMonitor workersMon(mWaitingWorkersMon);3560 workersMon.Wait(PR_MIN(mWorkers.Count() / 20 + 1, 10));3561 }3562 mon.Enter();3563 // examine the queue again3564 if (mPendingQ.Count() > mWaitingWorkers)3565 {3566 // we need one more worker3567 nsresult rv = CreateWorker();3568 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create one more worker thread");3569 rv = rv;3570 }3571 }3572 3573 # endif3574 #else3575 3576 OnIncomingRequest(aSenderID, op, aDataLen);3577 3578 #endif3579 3580 3283 return NS_OK; 3581 3284 } … … 3675 3378 //----------------------------------------------------------------------------- 3676 3379 3677 #if defined(DCONNECT_WITH_IPRT_REQ_POOL)3678 3380 /** 3679 3381 * Function called by the request thread pool to process a incoming request in … … 3687 3389 RTMemFree(aData); 3688 3390 } 3689 #endif3690 3391 3691 3392 void -
trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h
r103476 r103488 36 36 * 37 37 * ***** END LICENSE BLOCK ***** */ 38 39 // DConnect service is multithreaded by default...40 #if !defined(DCONNECT_SINGLETHREADED) && !defined(DCONNECT_MULTITHREADED)41 #define DCONNECT_MULTITHREADED42 # ifdef VBOX43 # define DCONNECT_WITH_IPRT_REQ_POOL44 # endif45 #endif46 47 38 #include "ipcIDConnectService.h" 48 39 #include "ipcdclient.h" … … 61 52 #include "xptinfo.h" 62 53 63 #if defined(DCONNECT_MULTITHREADED) 64 # if defined(DCONNECT_WITH_IPRT_REQ_POOL) 65 66 # include <iprt/req.h> 67 68 # else /* !DCONNECT_WITH_IPRT_REQ_POOL*/ 69 70 #include "ipcList.h" 71 72 struct DConnectOp; 73 74 struct DConnectRequest : public ipcListNode<DConnectRequest> 75 { 76 DConnectRequest (PRUint32 aPeer, const DConnectOp *aOp, PRUint32 aOpLen) 77 : peer(aPeer) 78 , opLen(aOpLen) 79 { 80 op = (const DConnectOp *) malloc(aOpLen); 81 memcpy ((void *) op, aOp, aOpLen); 82 } 83 ~DConnectRequest() { free((void *) op); } 84 85 const PRUint32 peer; 86 const DConnectOp *op; 87 const PRUint32 opLen; 88 }; 89 90 # endif // !DCONNECT_WITH_IPRT_REQ_POOL 91 #endif // DCONNECT_MULTITHREADED 54 #include <iprt/req.h> 92 55 93 56 class nsIException; … … 283 246 NS_HIDDEN_(void) OnInvoke(PRUint32 peer, const struct DConnectInvoke *, PRUint32 opLen); 284 247 285 #if defined(DCONNECT_MULTITHREADED)286 # if defined(DCONNECT_WITH_IPRT_REQ_POOL)287 248 static DECLCALLBACK(void) ProcessMessageOnWorkerThread(ipcDConnectService *aThis, PRUint32 aSenderID, void *aData, PRUint32 aDataLen); 288 # else289 NS_HIDDEN_(nsresult) CreateWorker();290 # endif291 #endif292 249 293 250 private: … … 314 271 PRBool mDisconnected; 315 272 316 // member is never initialized or used, no point in wasting memory or making317 // someone believe it contains anything relevant318 #ifndef VBOX319 // our IPC client ID320 PRUint32 mSelfID;321 #endif322 323 273 // global lock to protect access to protect DConnectStub::QueryInterface() 324 274 // (we cannot use mStubLock because it isn't supposed to be held long, 325 275 // like in case of an IPC call and such) 326 276 RTSEMFASTMUTEX mStubQILock; 327 328 #if defined(DCONNECT_MULTITHREADED)329 # if defined(DCONNECT_WITH_IPRT_REQ_POOL)330 331 277 /** Request pool. */ 332 278 RTREQPOOL mhReqPool; 333 334 # else335 336 friend class DConnectWorker;337 338 // pool of worker threads to serve incoming requests339 nsVoidArray mWorkers;340 // queue of pending requests341 ipcList<DConnectRequest> mPendingQ;342 // monitor to protect mPendingQ343 PRMonitor *mPendingMon;344 // number of waiting workers345 PRUint32 mWaitingWorkers;346 // monitor used to wait on changes in mWaitingWorkers.347 PRMonitor *mWaitingWorkersMon;348 # endif349 #endif350 279 351 280 // global ipcDConnectService instance for internal usage
Note:
See TracChangeset
for help on using the changeset viewer.