This PR fixes a random FAIL_FAST crash when completing an async call and fixes an issue where if you call XAsyncGetResults before a call is complete the async block's internal context gets corrupted.
This change replaces LocklessList.h with LocklessQueue.h. LocklessQueue performs much better than LocklessList and allows new items to be added to a task queue with zero allocations. Overall performance of task queue inserts and removals is about 6x faster.
If a task queue is executing a deferred callback and is asked to terminate, it's possible the the deferred call runs while the queue task port is destructing. This can cause a crash.
This also changes cleanup so if you don't have a payload to return your cleanup op is called at the end of work processing. this can help with shutdown.
XAsyncCancel now routes through the provider, which must cal XAsyncComplete(E_ABORT) to cancel a calll. This allows for non-cancelable async calls like XAL shutdown.
This fixes a bug Luca found where if you have a delayed callback in a task queue and you close a composite queue the delayed callback can fire immediately. This happened because when canceling the callback timer for queue rundown we didn't clear the due time field, so when we started the timer back up we thought the call at the head of the list was due.
Other changes:
* Rundown logic at final release hardened. It was possible to race here and rundown a queue that wasn't destined to die.
* Additional tests.
* Fix tests for added Begin opcode.
Queue termination was intended only to be performed by the creator of the main queue, with composite queues simply closing their handles. That's not how XAL is using it though, so this change allows for termination of composite queues. Behavior changes are as follows:
* Terminating a composite queue terminates that queue, running through operations for that composite queue and clearing them out of the port. The port will remain active for other queues to use.
* Closing a queue handle inside a termination callback would deadlock for thread pool based queues, since the final close handle will destroy the thread pool and wait for all calls to complete. Now this works for both Win32 and STL based thread pools.
* Queue monitor callbacks were only active for the primary queue -- they were a NOP for composite queues. This is now fixed.
This change incorporates api breaking changes from Windows done as a result of design feedback.
Specifically:
Design Changes
* AsyncQueue.h -> XTaskQueue.h
* New task queue termination APIs
* New task queue wait apis
* Lots of small changes based on design feedback
* Better perf - task queue is now lock free when submitting new items
File Renames
* Async.h -> XAsync.h, AsyncProvider.h -> XAsyncProvider.h.
Guideline Updates
* No more foo_handle_t. Replaced by XFooHandle.
* All APIs prefixed with X and a common category, like XAsync or XTaskQueue
This PR primarily moves async queue away from std::mutex and instead uses spin locks, at least on multi-processor systems. The reason for this is to prevent context switches while adding things to the queue, which can slow down perf critical threads.
The async queue implementation is also now built on an interface abstraction, which will make interoperability between Windows code and libHttpClient easier.
Finally, there are some API additions / changes:
DuplicateAsyncQueueHandle now returns a HRESULT and has the new handle as an out-param. The semantics haven't changed, but this signature mates better with other Win32 "duplicate" APIs and allows us a little more freedom in the implementation later on.
There are two new dispatch modes: SerializedThreadPool uses the thread pool, but ensures that queue calls are run in series through it instead of in parallel. This is useful if you want to use a thread pool as your completion dispatch mode, but still want things to always come in order. Immediate dispatch mode doesn't queue at all and just invokes the callback immediately on the submitting thread. This is a useful utility mechanism for chaining async calls together.
RemoveAsyncQueueCallbacks can now accept a nullptr as the callback function pointer to act as a wild card. This must be used with caution, since you can remove any callback (not just yours), but it's kind of necessary to support lambdas.
* Merge with windows tree
* Use C++11 for deleting assignment/copy ctor
* merge changes from Windows
* Add unit tests, updates from Windows
* rebuild projects
* Move to standard snprintf
* Update non-windows error code
* Signal completion after completion callback
* Waits for non-win32
* Minor hardening
* fix merge conflict
* Missing filter
* PR feedback
* typo
* Update from GameCore spec review
* Merge from Windows tree
* PR feedback
* PR feedback
* Fix race condition in worker callback
* PR feedback
Significant build refactoring and improvement including
-Single sln file for vs2015 and 2017
-Building dependencies from source and getting rid of nugets
-Improve props files
-Added internal props file with common build properties shared among all projects
* Merge with windows tree
* Use C++11 for deleting assignment/copy ctor
* merge changes from Windows
* Add unit tests, updates from Windows
* rebuild projects
* Move to standard snprintf
* Update non-windows error code
* Signal completion after completion callback
* Waits for non-win32
* Minor hardening
* fix merge conflict
* Missing filter
* PR feedback
* typo
* Merge with windows tree
* Use C++11 for deleting assignment/copy ctor
* merge changes from Windows
* Add unit tests, updates from Windows
* rebuild projects
* Move to standard snprintf
* Update non-windows error code