aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firebase/Auth/Docs/threading.md
diff options
context:
space:
mode:
Diffstat (limited to 'Firebase/Auth/Docs/threading.md')
-rw-r--r--Firebase/Auth/Docs/threading.md119
1 files changed, 119 insertions, 0 deletions
diff --git a/Firebase/Auth/Docs/threading.md b/Firebase/Auth/Docs/threading.md
new file mode 100644
index 0000000..2f5b782
--- /dev/null
+++ b/Firebase/Auth/Docs/threading.md
@@ -0,0 +1,119 @@
+# Firebase Auth Thread Safety
+
+This document describes how Firebase Auth maintains thread-safety. The Firebase
+Auth library (not including Firebase Auth UI and Auth Provider UIs for now)
+must be thread-safe, meaning deveopers are free to call any method in any
+thread at any time. Thus, all code that may take part in race conditions must
+be protected in some way.
+
+## Local Synchronization
+
+When contested data and accessing code is limited in scope, for example,
+a mutable array accessed only by two methods, a `@synchronized` directive is
+probably the simplest solution. Make sure the object to be locked on is not
+`nil`, e.g., `self`.
+
+## Global Work Queue
+
+A more scalable solution used throughout the current code base is to execute
+all potentially conflicting code in the same serial dispatch queue, which is
+referred as "the auth global work queue", or in some other serial queue that
+has its target queue set to this auth global work queue. This way we don't
+have to think about which variables may be contested. We only need to make
+sure all public APIs that may have thread-safety issues make the dispatch.
+The auth global work queue is defined in
+[FIRAuthGlobalWorkQueue.h](../Source/Private/FIRAuthGlobalWorkQueue.h)
+and any serial task queue created by
+[FIRAuthSerialTaskQueue.h](../Source/Private/FIRAuthSerialTaskQueue.h)
+already has its target set properly.
+
+In following sub-sections, we divided methods into three categories, according
+to the two criteria below:
+
+1. Whether the method is public or private:
+ * A public method can be directly called by developers.
+ * A private method can only be called by our own code.
+2. Whether the method is synchronous or asynchronous.
+ * A synchronous method returns some value or object in the calling
+ thread immediately.
+ * An asynchronous method returns nothing but calls the callback provided
+ by the caller at some point in future.
+
+### Public Asynchronous Methods
+
+Unless it's a simple wrapper of another public asynchronous method, a public
+asynchronous method shall
+
+* Dispatch asynchronously to the auth global work queue immediately.
+* Dispatch asynchronously to the main queue before calling the callback.
+ This is to make developers' life easier so they don't have to manage
+ thread-safety.
+
+The code would look like:
+
+```objectivec
+- (void)doSomethingWithCompletion:(nullable CompletionBlock)completion {
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
+ // Do things...
+ if (completion) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completion(args);
+ });
+ }
+ });
+}
+```
+
+### Public Synchronous Methods
+
+A public synchronous method that needs protection shall dispatch
+*synchronously* to the auth global work queue for its work. The code would
+look like:
+
+```objectivec
+- (ReturnType)something {
+ __block ReturnType result;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ // Compute result.
+ result = computedResult;
+ });
+ return result;
+}
+```
+
+**But don't call methods protected this way from private methods, or a
+deadlock would occur.** This is because you are not supposed to
+`dispatch_sync` to the queue you're already in. This can be easily worked
+around by creating an equivalent private synchronous method to be called by
+both public and private methods and making the public synchronous method a
+wrapper of that. For example,
+
+```objectivec
+- (ReturnType)somethingInternal {
+ // Compute result.
+ return computedResult;
+}
+
+- (ReturnType)something {
+ __block ReturnType result;
+ dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
+ result = [self somethingInternal];
+ });
+ return result;
+}
+```
+
+### Private Methods
+
+Generally speaking there is nothing special needed to be done for private
+methods:
+
+* The calling code should already be in the auth global work queue.
+* The callback, if any, is provided by our own code, so it expects to called
+ in the auth global work queue as well. This is usually already the case,
+ unless the method pass the callback to some other asychronous methods
+ outside our library, in which case we need to manually make the callback
+ called in the auth global work queue.
+
+Just beware you can't call public synchronous methods protected by the auth
+global work queue from private methods as stated in the preceding sub-section.