136 lines
3.9 KiB
C++
136 lines
3.9 KiB
C++
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
#include <gtest/gtest.h>
|
|
#include "bthread/bthread.h"
|
|
#include "bthread/singleton_on_bthread_once.h"
|
|
#include "bthread/task_control.h"
|
|
|
|
namespace bthread {
|
|
extern TaskControl* g_task_control;
|
|
}
|
|
|
|
namespace {
|
|
|
|
bthread_once_t g_bthread_once_control;
|
|
bool g_bthread_once_started = false;
|
|
butil::atomic<int> g_bthread_once_count(0);
|
|
|
|
void init_routine() {
|
|
bthread_usleep(2000 * 1000);
|
|
g_bthread_once_count.fetch_add(1, butil::memory_order_relaxed);
|
|
}
|
|
|
|
void bthread_once_task() {
|
|
bthread_once(&g_bthread_once_control, init_routine);
|
|
// `init_routine' only be called once.
|
|
ASSERT_EQ(1, g_bthread_once_count.load(butil::memory_order_relaxed));
|
|
}
|
|
|
|
void* first_bthread_once_task(void*) {
|
|
g_bthread_once_started = true;
|
|
bthread_once_task();
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void* other_bthread_once_task(void*) {
|
|
bthread_once_task();
|
|
return NULL;
|
|
}
|
|
|
|
TEST(BthreadOnceTest, once) {
|
|
bthread_t bid;
|
|
ASSERT_EQ(0, bthread_start_background(
|
|
&bid, NULL, first_bthread_once_task, NULL));
|
|
while (!g_bthread_once_started) {
|
|
bthread_usleep(1000);
|
|
}
|
|
ASSERT_NE(nullptr, bthread::g_task_control);
|
|
int concurrency = bthread::g_task_control->concurrency();
|
|
LOG(INFO) << "concurrency: " << concurrency;
|
|
ASSERT_GT(concurrency, 0);
|
|
std::vector<bthread_t> bids(concurrency * 100);
|
|
for (auto& id : bids) {
|
|
ASSERT_EQ(0, bthread_start_background(
|
|
&id, NULL, other_bthread_once_task, NULL));
|
|
}
|
|
bthread_once_task();
|
|
|
|
for (auto& id : bids) {
|
|
bthread_join(id, NULL);
|
|
}
|
|
bthread_join(bid, NULL);
|
|
}
|
|
|
|
bool g_bthread_started = false;
|
|
butil::atomic<int> g_bthread_singleton_count(0);
|
|
|
|
class BthreadSingleton {
|
|
public:
|
|
BthreadSingleton() {
|
|
bthread_usleep(2000 * 1000);
|
|
g_bthread_singleton_count.fetch_add(1, butil::memory_order_relaxed);
|
|
}
|
|
};
|
|
|
|
void get_bthread_singleton() {
|
|
auto instance = bthread::get_leaky_singleton<BthreadSingleton>();
|
|
ASSERT_NE(nullptr, instance);
|
|
// Only one BthreadSingleton instance has been created.
|
|
ASSERT_EQ(1, g_bthread_singleton_count.load(butil::memory_order_relaxed));
|
|
}
|
|
|
|
void* first_get_bthread_singleton(void*) {
|
|
g_bthread_started = true;
|
|
get_bthread_singleton();
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void* get_bthread_singleton(void*) {
|
|
get_bthread_singleton();
|
|
return NULL;
|
|
}
|
|
|
|
// Singleton will definitely not cause deadlock,
|
|
// even if constructor of T will hang the bthread.
|
|
TEST(BthreadOnceTest, singleton) {
|
|
bthread_t bid;
|
|
ASSERT_EQ(0, bthread_start_background(
|
|
&bid, NULL, first_get_bthread_singleton, NULL));
|
|
while (!g_bthread_started) {
|
|
bthread_usleep(1000);
|
|
}
|
|
ASSERT_NE(nullptr, bthread::g_task_control);
|
|
int concurrency = bthread::g_task_control->concurrency();
|
|
LOG(INFO) << "concurrency: " << concurrency;
|
|
ASSERT_GT(concurrency, 0);
|
|
std::vector<bthread_t> bids(concurrency * 100);
|
|
for (auto& id : bids) {
|
|
ASSERT_EQ(0, bthread_start_background(
|
|
&id, NULL, get_bthread_singleton, NULL));
|
|
}
|
|
get_bthread_singleton();
|
|
|
|
for (auto& id : bids) {
|
|
bthread_join(id, NULL);
|
|
}
|
|
bthread_join(bid, NULL);
|
|
}
|
|
|
|
} |