layers: Kill false thread errors re: command pool

Change the transitivity of usage counters such that only externally
synchronized command buffers mark their command pool as being an active
writer.

Added additional tracking for non-externally sync'd command buffers
s.t. command pool reset and destroy operations detect usage races.

Change-Id: I839ac8a5902a42ea1a1ba72db37cda2466516d11
diff --git a/layers/threading.cpp b/layers/threading.cpp
index 08020ad..8d4610e 100644
--- a/layers/threading.cpp
+++ b/layers/threading.cpp
@@ -470,6 +470,53 @@
     }
 }
 
+VKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
+    dispatch_key key = get_dispatch_key(device);
+    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
+    VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
+    VkResult result;
+    bool threadChecks = startMultiThread();
+    if (threadChecks) {
+        startReadObject(my_data, device);
+        startWriteObject(my_data, commandPool);
+        // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands)
+        my_data->c_VkCommandPoolContents.startWrite(my_data->report_data, commandPool);
+        // Host access to commandPool must be externally synchronized
+    }
+    result = pTable->ResetCommandPool(device, commandPool, flags);
+    if (threadChecks) {
+        finishReadObject(my_data, device);
+        finishWriteObject(my_data, commandPool);
+        my_data->c_VkCommandPoolContents.finishWrite(commandPool);
+        // Host access to commandPool must be externally synchronized
+    } else {
+        finishMultiThread();
+    }
+    return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
+    dispatch_key key = get_dispatch_key(device);
+    layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
+    VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
+    bool threadChecks = startMultiThread();
+    if (threadChecks) {
+        startReadObject(my_data, device);
+        startWriteObject(my_data, commandPool);
+        // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands)
+        my_data->c_VkCommandPoolContents.startWrite(my_data->report_data, commandPool);
+        // Host access to commandPool must be externally synchronized
+    }
+    pTable->DestroyCommandPool(device, commandPool, pAllocator);
+    if (threadChecks) {
+        finishReadObject(my_data, device);
+        finishWriteObject(my_data, commandPool);
+        my_data->c_VkCommandPoolContents.finishWrite(commandPool);
+        // Host access to commandPool must be externally synchronized
+    } else {
+        finishMultiThread();
+    }
+}
 }  // namespace threading
 
 // vk_layer_logging.h expects these to be defined
diff --git a/layers/threading.h b/layers/threading.h
index 4404692..f2e07fe 100644
--- a/layers/threading.h
+++ b/layers/threading.h
@@ -266,6 +266,8 @@
     counter<VkInstance> c_VkInstance;
     counter<VkQueue> c_VkQueue;
 #ifdef DISTINCT_NONDISPATCHABLE_HANDLES
+    // Special entry to allow tracking of command pool Reset and Destroy
+    counter<VkCommandPool> c_VkCommandPoolContents;
     counter<VkBuffer> c_VkBuffer;
     counter<VkBufferView> c_VkBufferView;
     counter<VkCommandPool> c_VkCommandPool;
@@ -299,6 +301,9 @@
     counter<VkDebugUtilsMessengerEXT> c_VkDebugUtilsMessengerEXT;
     counter<VkAccelerationStructureNVX> c_VkAccelerationStructureNVX;
 #else   // DISTINCT_NONDISPATCHABLE_HANDLES
+    // Special entry to allow tracking of command pool Reset and Destroy
+    counter<uint64_t> c_VkCommandPoolContents;
+
     counter<uint64_t> c_uint64_t;
 #endif  // DISTINCT_NONDISPATCHABLE_HANDLES
 
@@ -314,6 +319,7 @@
           c_VkDevice("VkDevice", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT),
           c_VkInstance("VkInstance", VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT),
           c_VkQueue("VkQueue", VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT),
+          c_VkCommandPoolContents("VkCommandPool", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT),
 #ifdef DISTINCT_NONDISPATCHABLE_HANDLES
           c_VkBuffer("VkBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT),
           c_VkBufferView("VkBufferView", VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT),
@@ -432,7 +438,10 @@
     std::unique_lock<std::mutex> lock(command_pool_lock);
     VkCommandPool pool = command_pool_map[object];
     lock.unlock();
-    startReadObject(my_data, pool);
+    // We set up a read guard against the "Contents" counter to catch conflict vs. vkResetCommandPool and vkDestroyCommandPool
+    // while *not* establishing a read guard against the command pool counter itself to avoid false postives for
+    // non-externally sync'd command buffers
+    my_data->c_VkCommandPoolContents.startRead(my_data->report_data, pool);
     my_data->c_VkCommandBuffer.startRead(my_data->report_data, object);
 }
 static void finishReadObject(struct layer_data *my_data, VkCommandBuffer object) {
@@ -440,6 +449,6 @@
     std::unique_lock<std::mutex> lock(command_pool_lock);
     VkCommandPool pool = command_pool_map[object];
     lock.unlock();
-    finishReadObject(my_data, pool);
+    my_data->c_VkCommandPoolContents.finishRead(pool);
 }
 #endif  // THREADING_H
diff --git a/scripts/threading_generator.py b/scripts/threading_generator.py
index 5cfb4d7..74d4b8c 100644
--- a/scripts/threading_generator.py
+++ b/scripts/threading_generator.py
@@ -376,6 +376,8 @@
             'vkDestroyInstance',
             'vkAllocateCommandBuffers',
             'vkFreeCommandBuffers',
+            'vkResetCommandPool',
+            'vkDestroyCommandPool',
             'vkCreateDebugReportCallbackEXT',
             'vkDestroyDebugReportCallbackEXT',
             'vkAllocateDescriptorSets',