aboutsummaryrefslogtreecommitdiffstats
path: root/src/google/protobuf/stubs/once.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/stubs/once.cc')
-rw-r--r--src/google/protobuf/stubs/once.cc81
1 files changed, 35 insertions, 46 deletions
diff --git a/src/google/protobuf/stubs/once.cc b/src/google/protobuf/stubs/once.cc
index 889c647..5b7af9c 100644
--- a/src/google/protobuf/stubs/once.cc
+++ b/src/google/protobuf/stubs/once.cc
@@ -1,6 +1,6 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -35,65 +35,54 @@
// This header is intended to be included only by internal .cc files and
// generated .pb.cc files. Users should not use this directly.
-#include <google/protobuf/stubs/once.h>
-
-#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
-
#ifdef _WIN32
#include <windows.h>
-#else
-#include <sched.h>
#endif
-#include <google/protobuf/stubs/atomicops.h>
+#include <google/protobuf/stubs/once.h>
namespace google {
namespace protobuf {
-namespace {
-
-void SchedYield() {
#ifdef _WIN32
- Sleep(0);
-#else // POSIX
- sched_yield();
-#endif
+
+struct ProtobufOnceInternal {
+ ProtobufOnceInternal() {
+ InitializeCriticalSection(&critical_section);
+ }
+ ~ProtobufOnceInternal() {
+ DeleteCriticalSection(&critical_section);
+ }
+ CRITICAL_SECTION critical_section;
+};
+
+ProtobufOnceType::~ProtobufOnceType()
+{
+ delete internal_;
+ internal_ = NULL;
}
-} // namespace
+ProtobufOnceType::ProtobufOnceType() {
+ // internal_ may be non-NULL if Init() was already called.
+ if (internal_ == NULL) internal_ = new ProtobufOnceInternal;
+}
-void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure) {
- internal::AtomicWord state = internal::Acquire_Load(once);
- // Fast path. The provided closure was already executed.
- if (state == ONCE_STATE_DONE) {
- return;
- }
- // The closure execution did not complete yet. The once object can be in one
- // of the two following states:
- // - UNINITIALIZED: We are the first thread calling this function.
- // - EXECUTING_CLOSURE: Another thread is already executing the closure.
- //
- // First, try to change the state from UNINITIALIZED to EXECUTING_CLOSURE
- // atomically.
- state = internal::Acquire_CompareAndSwap(
- once, ONCE_STATE_UNINITIALIZED, ONCE_STATE_EXECUTING_CLOSURE);
- if (state == ONCE_STATE_UNINITIALIZED) {
- // We are the first thread to call this function, so we have to call the
- // closure.
- closure->Run();
- internal::Release_Store(once, ONCE_STATE_DONE);
- } else {
- // Another thread has already started executing the closure. We need to
- // wait until it completes the initialization.
- while (state == ONCE_STATE_EXECUTING_CLOSURE) {
- // Note that futex() could be used here on Linux as an improvement.
- SchedYield();
- state = internal::Acquire_Load(once);
- }
+void ProtobufOnceType::Init(void (*init_func)()) {
+ // internal_ may be NULL if we're still in dynamic initialization and the
+ // constructor has not been called yet. As mentioned in once.h, we assume
+ // that the program is still single-threaded at this time, and therefore it
+ // should be safe to initialize internal_ like so.
+ if (internal_ == NULL) internal_ = new ProtobufOnceInternal;
+
+ EnterCriticalSection(&internal_->critical_section);
+ if (!initialized_) {
+ init_func();
+ initialized_ = true;
}
+ LeaveCriticalSection(&internal_->critical_section);
}
+#endif
+
} // namespace protobuf
} // namespace google
-
-#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY