[ovs-dev] [PATCH 11/15] datapath-windows: Add RefCount.h
Samuel Ghinet
sghinet at cloudbasesolutions.com
Wed Aug 6 16:14:42 UTC 2014
Add RefCount.h
The struct that needs to benefit of reference counting should have an "OVS_REF_COUNT" field as the
first field in that struct.
What it does:
* It helps shortening the time a spin lock / rw lock is held (the spin lock & rw lock block the cpu).
* It allows deferred object destruction / deletion.
How it works:
Say we have a list of OVS_FLOWs, where OVS_FLOW uses OVS_REF_COUNT.
* The OVS_REF_COUNT must be initialized to 0 at object creation.
* Assign a destruction function to the func ptr "Destroy" of OVS_REF_COUNT.
* When you need to retrieve a ptr to an OVS_FLOW, from the list, you must do the following:
*** lock the OVS_FLOW list for read (obviously)
*** do the lookup: a ptr to an existing OVS_FLOW, pFlow, is found.
*** call "OVS_REFCOUNT_REFERENCE(pFlow);" - by doing so, you deny destruction of pFlow, while the object
is referenced, ensuring that you keep a valid pointer to a flow.
*** unlock the list
*** return pFlow.
* When you need to modify fields in the pFlow, use the rw lock / spinlock field of pFlow.
* When you no longer need the ptr, use "OVS_REFCOUNT_DEREFERENCE(pFlow);"
* When you need to do deferred deletion, call "OVS_REFCOUNT_DESTROY(pFlow);": this will
mark the pFlow for deletion. If the object is not referenced, it will be destroyed immediately. Otherwise,
it will be destroyed when the refCount = 0.
Signed-off-by: Samuel Ghinet <sghinet at cloudbasesolutions.com>
---
datapath-windows/ovsext/Core/RefCount.h | 274 +++++++++++++++++++++++++
datapath-windows/ovsext/ovsext.vcxproj | 1 +
datapath-windows/ovsext/ovsext.vcxproj.filters | 3 +
3 files changed, 278 insertions(+)
create mode 100644 datapath-windows/ovsext/Core/RefCount.h
diff --git a/datapath-windows/ovsext/Core/RefCount.h b/datapath-windows/ovsext/Core/RefCount.h
new file mode 100644
index 0000000..3694e37
--- /dev/null
+++ b/datapath-windows/ovsext/Core/RefCount.h
@@ -0,0 +1,274 @@
+/*
+Copyright 2014 Cloudbase Solutions Srl
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http ://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#pragma once
+
+#include "precomp.h"
+
+#ifdef DBG
+#define OVS_USE_REFCOUNT_CALL_STACK 1
+#else
+#define OVS_USE_REFCOUNT_CALL_STACK 0
+#endif
+
+#if OVS_USE_REFCOUNT_CALL_STACK
+#define OVS_REFCOUNT_MAX_THREAD_COUNT 16
+#define OVS_REFCOUNT_MAX_FUNC_COUNT 10
+
+C_ASSERT(OVS_REFCOUNT_MAX_THREAD_COUNT <= 64);
+#endif
+
+//NOTE: must be the first field of any struct using the OVS_REF_COUNT
+typedef struct _OVS_REF_COUNT
+{
+#if OVS_USE_REFCOUNT_CALL_STACK
+ //for debugging purposes: when a refCount is increased, it is first added to countsPerThread[currentThreadNumber]
+ //then the func name (__FUNCTION__) will be placed at funcs[curThreadNumber][refCountPerCurrentThread]
+ //if there is not enough room to store the func name in the stack (i.e. refCount >= OVS_REFCOUNT_MAX_FUNC_COUNT) => we consider it a bug
+ const char* funcs[OVS_REFCOUNT_MAX_THREAD_COUNT][OVS_REFCOUNT_MAX_FUNC_COUNT];
+ ULONG refCountsPerThread[OVS_REFCOUNT_MAX_THREAD_COUNT];
+ PKTHREAD threads[OVS_REFCOUNT_MAX_THREAD_COUNT];
+ ULONG noOfThreads;
+#endif
+
+ //if refCount > 0, the object deletion will be postponed
+ //it is used so that we can keep a pointer to the object, while allowing it to be modified (but not deleted) by other threads.
+ volatile ULONG refCount;
+ //if the object should be destroyed, but some thread currently holds a reference to it, it will be marked for deletion instead.
+ //when the refCount reaches 0, if deletetionPending is set, the dereference function will destroy the object.
+ volatile BOOLEAN deletionPending;
+
+ VOID (*Destroy)(VOID*);
+}OVS_REF_COUNT;
+
+extern NDIS_RW_LOCK_EX* g_pRefRwLock;
+
+/**************************************/
+
+static __inline VOID RefCount_DereferenceOnly(VOID* pObj)
+{
+ LOCK_STATE_EX lockState;
+ OVS_REF_COUNT* pRefCount = pObj;
+
+ if (!pObj)
+ {
+ return;
+ }
+
+ NdisAcquireRWLockWrite(g_pRefRwLock, &lockState, 0);
+
+ OVS_CHECK(pRefCount->refCount > 0);
+#if OVS_USE_REFCOUNT_CALL_STACK
+ {
+ ULONG threadNumber = MAXULONG;
+ ULONG curThreadRefCount = 0;
+ PKTHREAD pThread = NULL;
+
+ OVS_CHECK(pRefCount->refCount < OVS_REFCOUNT_MAX_FUNC_COUNT);
+ pThread = KeGetCurrentThread();
+
+ for (ULONG i = 0; i < OVS_REFCOUNT_MAX_THREAD_COUNT; ++i)
+ {
+ if (pRefCount->threads[i] == pThread)
+ {
+ threadNumber = i;
+ break;
+ }
+ }
+
+ OVS_CHECK(threadNumber != MAXULONG);
+
+ OVS_CHECK(pRefCount->refCountsPerThread[threadNumber] > 0);
+ pRefCount->refCountsPerThread[threadNumber]--;
+ curThreadRefCount = pRefCount->refCountsPerThread[threadNumber];
+ pRefCount->funcs[threadNumber][curThreadRefCount] = NULL;
+
+ if (curThreadRefCount == 0)
+ {
+ pRefCount->threads[threadNumber] = NULL;
+ pRefCount->noOfThreads--;
+ }
+ }
+#endif
+ --pRefCount->refCount;
+
+ NdisReleaseRWLock(g_pRefRwLock, &lockState);
+}
+
+#define OVS_REFCOUNT_DEREFERENCE_ONLY(pObj) RefCount_DereferenceOnly(pObj)
+
+static __inline VOID RefCount_Dereference(VOID* pObj)
+{
+ LOCK_STATE_EX lockState;
+ OVS_REF_COUNT* pRefCount = pObj;
+
+ if (!pObj)
+ {
+ return;
+ }
+
+ OVS_CHECK(pRefCount->Destroy);
+
+ NdisAcquireRWLockWrite(g_pRefRwLock, &lockState, 0);
+
+ OVS_CHECK(pRefCount->refCount > 0);
+#if OVS_USE_REFCOUNT_CALL_STACK
+ {
+ ULONG threadNumber = MAXULONG;
+ ULONG curThreadRefCount = 0;
+ PKTHREAD pThread = NULL;
+
+ OVS_CHECK(pRefCount->refCount < OVS_REFCOUNT_MAX_FUNC_COUNT);
+ pThread = KeGetCurrentThread();
+
+ for (ULONG i = 0; i < OVS_REFCOUNT_MAX_THREAD_COUNT; ++i)
+ {
+ if (pRefCount->threads[i] == pThread)
+ {
+ threadNumber = i;
+ break;
+ }
+ }
+
+ OVS_CHECK(threadNumber != MAXULONG);
+
+ OVS_CHECK(pRefCount->refCountsPerThread[threadNumber] > 0);
+ pRefCount->refCountsPerThread[threadNumber]--;
+ curThreadRefCount = pRefCount->refCountsPerThread[threadNumber];
+ pRefCount->funcs[threadNumber][curThreadRefCount] = NULL;
+
+ if (curThreadRefCount == 0)
+ {
+ pRefCount->threads[threadNumber] = NULL;
+ pRefCount->noOfThreads--;
+ }
+ }
+#endif
+ --pRefCount->refCount;
+
+ if (pRefCount->refCount == 0 && pRefCount->deletionPending)
+ {
+ pRefCount->Destroy(pObj);
+ }
+
+ NdisReleaseRWLock(g_pRefRwLock, &lockState);
+}
+
+#define OVS_REFCOUNT_DEREFERENCE(pObj) {RefCount_Dereference(pObj); pObj = NULL; }
+
+static __inline VOID* RefCount_Reference(VOID* pObj, const char* funcName)
+{
+ LOCK_STATE_EX lockState;
+ OVS_REF_COUNT* pRefCount = pObj;
+
+ if (!pObj)
+ {
+ return NULL;
+ }
+
+ NdisAcquireRWLockWrite(g_pRefRwLock, &lockState, 0);
+
+ if (pRefCount->deletionPending)
+ {
+ pObj = NULL;
+ }
+ else
+ {
+#if OVS_USE_REFCOUNT_CALL_STACK
+ ULONG threadNumber = MAXULONG;
+ ULONG curThreadRefCount = 0;
+ PKTHREAD pThread = NULL;
+
+ OVS_CHECK(pRefCount->noOfThreads < OVS_REFCOUNT_MAX_THREAD_COUNT);
+
+ pThread = KeGetCurrentThread();
+
+ for (ULONG i = 0; i < OVS_REFCOUNT_MAX_THREAD_COUNT; ++i)
+ {
+ if (pRefCount->threads[i] == pThread)
+ {
+ threadNumber = i;
+ break;
+ }
+ }
+
+ if (threadNumber == MAXULONG)
+ {
+ OVS_CHECK(pRefCount->noOfThreads + 1 < OVS_REFCOUNT_MAX_THREAD_COUNT);
+
+ for (ULONG i = 0; i < OVS_REFCOUNT_MAX_THREAD_COUNT; ++i)
+ {
+ if (pRefCount->threads[i] == NULL)
+ {
+ pRefCount->threads[i] = pThread;
+ pRefCount->noOfThreads++;
+
+ threadNumber = i;
+ break;
+ }
+ }
+ }
+
+ OVS_CHECK(threadNumber != MAXULONG);
+
+ curThreadRefCount = pRefCount->refCountsPerThread[threadNumber];
+ OVS_CHECK(curThreadRefCount + 1 < OVS_REFCOUNT_MAX_FUNC_COUNT);
+
+ pRefCount->funcs[threadNumber][curThreadRefCount] = funcName;
+ pRefCount->refCountsPerThread[threadNumber]++;
+#else
+ UNREFERENCED_PARAMETER(funcName);
+#endif
+
+ ++pRefCount->refCount;
+ }
+
+ NdisReleaseRWLock(g_pRefRwLock, &lockState);
+
+ return pObj;
+}
+
+#define OVS_REFCOUNT_REFERENCE(pObj) RefCount_Reference(pObj, __FUNCTION__);
+
+static __inline VOID RefCount_Destroy(VOID* pObj)
+{
+ LOCK_STATE_EX lockState;
+ OVS_REF_COUNT* pRefCount = pObj;
+
+ if (!pObj)
+ {
+ return;
+ }
+
+ OVS_CHECK(pRefCount->Destroy);
+
+ NdisAcquireRWLockWrite(g_pRefRwLock, &lockState, 0);
+
+ if (pRefCount->refCount > 0)
+ {
+ pRefCount->deletionPending = TRUE;
+ }
+ else
+ {
+ pRefCount->Destroy(pObj);
+ }
+
+ NdisReleaseRWLock(g_pRefRwLock, &lockState);
+}
+
+#define OVS_REFCOUNT_DESTROY(pObj) { RefCount_Destroy(pObj); pObj = NULL; }
+
+#define OVS_REFCOUNT_DEREF_AND_DESTROY(pObj) { OVS_REFCOUNT_DEREFERENCE_ONLY(pObj); OVS_REFCOUNT_DESTROY(pObj); }
\ No newline at end of file
diff --git a/datapath-windows/ovsext/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj
index cce9df0..99aa6f6 100644
--- a/datapath-windows/ovsext/ovsext.vcxproj
+++ b/datapath-windows/ovsext/ovsext.vcxproj
@@ -75,6 +75,7 @@
<ClInclude Include="Core\IpHelper.h" />
<ClInclude Include="Core\Jhash.h" />
<ClInclude Include="Core\List.h" />
+ <ClInclude Include="Core\RefCount.h" />
<ClInclude Include="Core\SpookyHash.h" />
<ClInclude Include="Core\Types.h" />
<ClInclude Include="Core\Util.h" />
diff --git a/datapath-windows/ovsext/ovsext.vcxproj.filters b/datapath-windows/ovsext/ovsext.vcxproj.filters
index c23ca42..fc3ba3b 100644
--- a/datapath-windows/ovsext/ovsext.vcxproj.filters
+++ b/datapath-windows/ovsext/ovsext.vcxproj.filters
@@ -83,6 +83,9 @@
<ClInclude Include="Core\SpookyHash.h">
<Filter>Core</Filter>
</ClInclude>
+ <ClInclude Include="Core\RefCount.h">
+ <Filter>Core</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ovsext.rc" />
--
1.8.3.msysgit.0
More information about the dev
mailing list