1fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Protocol Buffers - Google's data interchange format
2fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Copyright 2008 Google Inc.  All rights reserved.
3fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// http://code.google.com/p/protobuf/
4fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
5fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Redistribution and use in source and binary forms, with or without
6fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// modification, are permitted provided that the following conditions are
7fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// met:
8fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
9fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions of source code must retain the above copyright
10fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// notice, this list of conditions and the following disclaimer.
11fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions in binary form must reproduce the above
12fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// copyright notice, this list of conditions and the following disclaimer
13fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// in the documentation and/or other materials provided with the
14fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// distribution.
15fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Neither the name of Google Inc. nor the names of its
16fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// contributors may be used to endorse or promote products derived from
17fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// this software without specific prior written permission.
18fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
19fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
31fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Author: kenton@google.com (Kenton Varda)
32fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
33fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#ifdef _WIN32
34fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <windows.h>
35fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#else
36fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <unistd.h>
37fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <pthread.h>
38fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif
39fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
40fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/stubs/once.h>
41fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/testing/googletest.h>
42fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <gtest/gtest.h>
43fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
44fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace google {
45fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace protobuf {
46fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace {
47fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
48fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleclass OnceInitTest : public testing::Test {
49fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville protected:
50fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  void SetUp() {
51fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    state_ = INIT_NOT_STARTED;
52fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    current_test_ = this;
53fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
54fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
55d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  // Since ProtobufOnceType is only allowed to be allocated in static storage,
56d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  // each test must use a different pair of ProtobufOnceType objects which it
57fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // must declare itself.
58d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  void SetOnces(ProtobufOnceType* once, ProtobufOnceType* recursive_once) {
59fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    once_ = once;
60fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    recursive_once_ = recursive_once;
61fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
62fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
63fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  void InitOnce() {
64fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    GoogleOnceInit(once_, &InitStatic);
65fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
66fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  void InitRecursiveOnce() {
67fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    GoogleOnceInit(recursive_once_, &InitRecursiveStatic);
68fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
69fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
70fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  void BlockInit() { init_blocker_.Lock(); }
71fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  void UnblockInit() { init_blocker_.Unlock(); }
72fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
73fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  class TestThread {
74fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   public:
75fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    TestThread(Closure* callback)
76fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        : done_(false), joined_(false), callback_(callback) {
77fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#ifdef _WIN32
78fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      thread_ = CreateThread(NULL, 0, &Start, this, 0, NULL);
79fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#else
80fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      pthread_create(&thread_, NULL, &Start, this);
81fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif
82fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
83fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    ~TestThread() {
84fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (!joined_) Join();
85fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
86fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
87fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    bool IsDone() {
88fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      MutexLock lock(&done_mutex_);
89fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return done_;
90fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
91fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    void Join() {
92fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      joined_ = true;
93fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#ifdef _WIN32
94fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      WaitForSingleObject(thread_, INFINITE);
95fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      CloseHandle(thread_);
96fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#else
97fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      pthread_join(thread_, NULL);
98fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif
99fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
100fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
101fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   private:
102fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#ifdef _WIN32
103fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    HANDLE thread_;
104fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#else
105fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    pthread_t thread_;
106fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif
107fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
108fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Mutex done_mutex_;
109fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    bool done_;
110fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    bool joined_;
111fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Closure* callback_;
112fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
113fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#ifdef _WIN32
114fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    static DWORD WINAPI Start(LPVOID arg) {
115fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#else
116fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    static void* Start(void* arg) {
117fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif
118fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      reinterpret_cast<TestThread*>(arg)->Run();
119fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return 0;
120fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
121fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
122fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    void Run() {
123fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      callback_->Run();
124fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      MutexLock lock(&done_mutex_);
125fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      done_ = true;
126fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
127fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  };
128fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
129fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  TestThread* RunInitOnceInNewThread() {
130fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return new TestThread(NewCallback(this, &OnceInitTest::InitOnce));
131fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
132fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  TestThread* RunInitRecursiveOnceInNewThread() {
133fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return new TestThread(NewCallback(this, &OnceInitTest::InitRecursiveOnce));
134fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  enum State {
137fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    INIT_NOT_STARTED,
138fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    INIT_STARTED,
139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    INIT_DONE
140fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  };
141fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  State CurrentState() {
142fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    MutexLock lock(&mutex_);
143fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return state_;
144fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
145fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  void WaitABit() {
147fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#ifdef _WIN32
148fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Sleep(1000);
149fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#else
150fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    sleep(1);
151fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif
152fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
153fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
154fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private:
155fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Mutex mutex_;
156fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Mutex init_blocker_;
157fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  State state_;
158d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  ProtobufOnceType* once_;
159d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  ProtobufOnceType* recursive_once_;
160fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
161fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  void Init() {
162fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    MutexLock lock(&mutex_);
163fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    EXPECT_EQ(INIT_NOT_STARTED, state_);
164fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    state_ = INIT_STARTED;
165fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    mutex_.Unlock();
166fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    init_blocker_.Lock();
167fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    init_blocker_.Unlock();
168fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    mutex_.Lock();
169fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    state_ = INIT_DONE;
170fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
171fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
172fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  static OnceInitTest* current_test_;
173fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  static void InitStatic() { current_test_->Init(); }
174fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  static void InitRecursiveStatic() { current_test_->InitOnce(); }
175fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
176fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
177fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleOnceInitTest* OnceInitTest::current_test_ = NULL;
178fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
179fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleGOOGLE_PROTOBUF_DECLARE_ONCE(simple_once);
180fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
181fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleTEST_F(OnceInitTest, Simple) {
182fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  SetOnces(&simple_once, NULL);
183fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_NOT_STARTED, CurrentState());
185fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  InitOnce();
186fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_DONE, CurrentState());
187fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
188fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // Calling again has no effect.
189fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  InitOnce();
190fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_DONE, CurrentState());
191fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
192fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
193fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleGOOGLE_PROTOBUF_DECLARE_ONCE(recursive_once1);
194fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleGOOGLE_PROTOBUF_DECLARE_ONCE(recursive_once2);
195fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
196fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleTEST_F(OnceInitTest, Recursive) {
197fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  SetOnces(&recursive_once1, &recursive_once2);
198fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
199fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_NOT_STARTED, CurrentState());
200fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  InitRecursiveOnce();
201fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_DONE, CurrentState());
202fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
203fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
204fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleGOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_once);
205fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
206fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleTEST_F(OnceInitTest, MultipleThreads) {
207fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  SetOnces(&multiple_threads_once, NULL);
208fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
209fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  scoped_ptr<TestThread> threads[4];
210fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_NOT_STARTED, CurrentState());
211fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int i = 0; i < 4; i++) {
212fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    threads[i].reset(RunInitOnceInNewThread());
213fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
214fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int i = 0; i < 4; i++) {
215fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    threads[i]->Join();
216fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
217fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_DONE, CurrentState());
218fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
219fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
220fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleGOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_blocked_once1);
221fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleGOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_blocked_once2);
222fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
223fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleTEST_F(OnceInitTest, MultipleThreadsBlocked) {
224fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  SetOnces(&multiple_threads_blocked_once1, &multiple_threads_blocked_once2);
225fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
226fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  scoped_ptr<TestThread> threads[8];
227fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_NOT_STARTED, CurrentState());
228fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
229fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  BlockInit();
230fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int i = 0; i < 4; i++) {
231fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    threads[i].reset(RunInitOnceInNewThread());
232fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
233fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int i = 4; i < 8; i++) {
234fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    threads[i].reset(RunInitRecursiveOnceInNewThread());
235fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
236fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
237fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  WaitABit();
238fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
239fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // We should now have one thread blocked inside Init(), four blocked waiting
240fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // for Init() to complete, and three blocked waiting for InitRecursive() to
241fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // complete.
242fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_STARTED, CurrentState());
243fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  UnblockInit();
244fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
245fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int i = 0; i < 8; i++) {
246fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    threads[i]->Join();
247fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
248fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  EXPECT_EQ(INIT_DONE, CurrentState());
249fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
250fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
251fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // anonymous namespace
252fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace protobuf
253fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace google
254