| 977 | |
| 978 | |
| 979 | bool initialize( |
| 980 | const Option<string>& delegate, |
| 981 | const Option<string>& readwriteAuthenticationRealm, |
| 982 | const Option<string>& readonlyAuthenticationRealm) |
| 983 | { |
| 984 | // TODO(benh): Return an error if attempting to initialize again |
| 985 | // with a different delegate than originally specified. |
| 986 | |
| 987 | // NOTE: Rather than calling `initialize` once at the root of the |
| 988 | // dependency tree; we currently rely on libprocess dependency |
| 989 | // declaration by invoking `initialize` prior to use. This is done |
| 990 | // frequently throughout the code base. Therefore we chose to use |
| 991 | // atomics rather than `Once`, as the overhead of a mutex and |
| 992 | // condition variable is excessive here. |
| 993 | |
| 994 | // Try and do the initialization or wait for it to complete. |
| 995 | |
| 996 | // If already initialized, there's nothing more to do. |
| 997 | // NOTE: This condition is true as soon as the thread performing |
| 998 | // initialization sets `initialize_complete` to `true` in the *middle* |
| 999 | // of initialization. This is done because some methods called by |
| 1000 | // initialization will themselves call `process::initialize`. |
| 1001 | if (initialize_started.load() && initialize_complete.load()) { |
| 1002 | // Return `false` because `process::initialize()` was already called. |
| 1003 | return false; |
| 1004 | |
| 1005 | } else { |
| 1006 | // NOTE: `compare_exchange_strong` needs an lvalue. |
| 1007 | bool expected = false; |
| 1008 | |
| 1009 | // Any thread that calls `initialize` prior to when `initialize_complete` |
| 1010 | // is set to `true` will reach this. |
| 1011 | |
| 1012 | // Atomically sets `initialize_started` to `true`. The thread that |
| 1013 | // successfully sets `initialize_started` to `true` will move on to |
| 1014 | // perform the initialization logic. All others will wait here for |
| 1015 | // initialization to complete. |
| 1016 | if (!initialize_started.compare_exchange_strong(expected, true)) { |
| 1017 | while (!initialize_complete.load()); |
| 1018 | |
| 1019 | // Return `false` because `process::initialize()` was already called. |
| 1020 | return false; |
| 1021 | } |
| 1022 | } |
| 1023 | |
| 1024 | #ifdef __WINDOWS__ |
| 1025 | // Initialize the Windows socket stack. This operation is idempotent. |
| 1026 | // NOTE: This call can report an error here if it determines it is |
| 1027 | // incompatible with the WSA version, so it is important to call this |
| 1028 | // even if we expect users of libprocess to have already started the |
| 1029 | // socket stack themselves. We exit the process under error condition |
| 1030 | // to prevent cryptic errors later. |
| 1031 | if (!net::wsa_initialize()) { |
| 1032 | EXIT(EXIT_FAILURE) << "WSA failed to initialize"; |
| 1033 | } |
| 1034 | #endif // __WINDOWS__ |
| 1035 | |
| 1036 | // We originally tried to leave SIGPIPE unblocked and to work |
no test coverage detected