MXS-2067: Replace SPINLOCK with pthread_mutex_t
Replaced the SPINLOCK implementation with pthread_mutex_t. The SPINLOCK interface is still used and will be removed later on.
This commit is contained in:
@ -12,103 +12,16 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/**
|
|
||||||
* @file spinlock.h
|
|
||||||
*
|
|
||||||
* Spinlock implementation for MaxScale.
|
|
||||||
*
|
|
||||||
* Spinlocks are cheap locks that can be used to protect short code blocks, they are
|
|
||||||
* generally wasteful as any blocked threads will spin, consuming CPU cycles, waiting
|
|
||||||
* for the lock to be released. However they are useful in that they do not involve
|
|
||||||
* system calls and are light weight when the expected wait time for a lock is low.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <maxscale/cdefs.h>
|
#include <maxscale/cdefs.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
MXS_BEGIN_DECLS
|
MXS_BEGIN_DECLS
|
||||||
|
|
||||||
#define SPINLOCK_PROFILE 0
|
#define SPINLOCK pthread_mutex_t
|
||||||
|
#define SPINLOCK_INIT PTHREAD_MUTEX_INITIALIZER
|
||||||
/**
|
#define spinlock_init(a) pthread_mutex_init(a, NULL)
|
||||||
* The spinlock structure.
|
#define spinlock_acquire(a) pthread_mutex_lock((pthread_mutex_t*)a)
|
||||||
*
|
#define spinlock_release(a) pthread_mutex_unlock((pthread_mutex_t*)a)
|
||||||
* In normal builds the structure merely contains a lock value which
|
|
||||||
* is 0 if the spinlock is not taken and greater than zero if it is held.
|
|
||||||
*
|
|
||||||
* In builds with the SPINLOCK_PROFILE option set this structure also holds
|
|
||||||
* a number of profile related fields that count the number of spins, number
|
|
||||||
* of waiting threads and the number of times the lock has been acquired.
|
|
||||||
*/
|
|
||||||
typedef struct spinlock
|
|
||||||
{
|
|
||||||
int lock; /*< Is the lock held? */
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
uint64_t spins; /*< Number of spins on this lock */
|
|
||||||
uint64_t maxspins; /*< Max no of spins to acquire lock */
|
|
||||||
uint64_t acquired; /*< No. of times lock was acquired */
|
|
||||||
uint64_t waiting; /*< No. of threads acquiring this lock */
|
|
||||||
uint64_t max_waiting; /*< Max no of threads waiting for lock */
|
|
||||||
uint64_t contended; /*< No. of times acquire was contended */
|
|
||||||
THREAD owner; /*< Last owner of this lock */
|
|
||||||
#endif
|
|
||||||
} SPINLOCK;
|
|
||||||
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
#define SPINLOCK_INIT {0, 0, 0, 0, 0, 0, 0, 0}
|
|
||||||
#else
|
|
||||||
#define SPINLOCK_INIT {0}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debugging macro for testing the state of a spinlock.
|
|
||||||
*
|
|
||||||
* @attention ONLY to be used in debugging context.
|
|
||||||
*/
|
|
||||||
#define SPINLOCK_IS_LOCKED(l) ((l)->lock != 0 ? true : false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise a spinlock.
|
|
||||||
*
|
|
||||||
* @param lock The spinlock to initialise.
|
|
||||||
*/
|
|
||||||
extern void spinlock_init(SPINLOCK* lock);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acquire a spinlock.
|
|
||||||
*
|
|
||||||
* @param lock The spinlock to acquire
|
|
||||||
*/
|
|
||||||
extern void spinlock_acquire(const SPINLOCK* lock);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acquire a spinlock if it is not already locked.
|
|
||||||
*
|
|
||||||
* @param lock The spinlock to acquire
|
|
||||||
* @return True if the spinlock was acquired, otherwise false
|
|
||||||
*/
|
|
||||||
extern bool spinlock_acquire_nowait(const SPINLOCK* lock);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Release a spinlock.
|
|
||||||
*
|
|
||||||
* @param lock The spinlock to release
|
|
||||||
*/
|
|
||||||
extern void spinlock_release(const SPINLOCK* lock);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Report statistics on a spinlock. This only has an effect if the
|
|
||||||
* spinlock code has been compiled with the SPINLOCK_PROFILE option set.
|
|
||||||
*
|
|
||||||
* NB A callback function is used to return the data rather than
|
|
||||||
* merely printing to a DCB in order to avoid a dependency on the DCB
|
|
||||||
* form the spinlock code and also to facilitate other uses of the
|
|
||||||
* statistics reporting.
|
|
||||||
*
|
|
||||||
* @param lock The spinlock to report on
|
|
||||||
* @param reporter The callback function to pass the statistics to
|
|
||||||
* @param hdl A handle that is passed to the reporter function
|
|
||||||
*/
|
|
||||||
extern void spinlock_stats(const SPINLOCK* lock, void (* reporter)(void*, char*, int), void* hdl);
|
|
||||||
|
|
||||||
MXS_END_DECLS
|
MXS_END_DECLS
|
||||||
|
|||||||
@ -43,7 +43,6 @@ add_library(maxscale-common SHARED
|
|||||||
service.cc
|
service.cc
|
||||||
session.cc
|
session.cc
|
||||||
session_command.cc
|
session_command.cc
|
||||||
spinlock.cc
|
|
||||||
ssl.cc
|
ssl.cc
|
||||||
users.cc
|
users.cc
|
||||||
utils.cc
|
utils.cc
|
||||||
|
|||||||
@ -945,7 +945,6 @@ static void server_parameter_free(SERVER_PARAM* tofree)
|
|||||||
*/
|
*/
|
||||||
static size_t server_get_parameter_nolock(const SERVER* server, const char* name, char* out, size_t size)
|
static size_t server_get_parameter_nolock(const SERVER* server, const char* name, char* out, size_t size)
|
||||||
{
|
{
|
||||||
mxb_assert(SPINLOCK_IS_LOCKED(&server->lock));
|
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
SERVER_PARAM* param = server->parameters;
|
SERVER_PARAM* param = server->parameters;
|
||||||
|
|
||||||
|
|||||||
@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
||||||
*
|
|
||||||
* Change Date: 2022-01-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2 or later of the General
|
|
||||||
* Public License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <maxscale/spinlock.h>
|
|
||||||
#include <maxbase/assert.h>
|
|
||||||
#include <maxbase/atomic.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
|
||||||
void spinlock_init(SPINLOCK* lock)
|
|
||||||
{
|
|
||||||
lock->lock = 0;
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
lock->spins = 0;
|
|
||||||
lock->maxspins = 0;
|
|
||||||
lock->acquired = 0;
|
|
||||||
lock->waiting = 0;
|
|
||||||
lock->max_waiting = 0;
|
|
||||||
lock->contended = 0;
|
|
||||||
lock->owner = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void spinlock_acquire(const SPINLOCK* const_lock)
|
|
||||||
{
|
|
||||||
SPINLOCK* lock = (SPINLOCK*)const_lock;
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
int spins = 0;
|
|
||||||
|
|
||||||
atomic_add(&(lock->waiting), 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (__sync_lock_test_and_set(&(lock->lock), 1))
|
|
||||||
{
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
atomic_add(&(lock->spins), 1);
|
|
||||||
spins++;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
if (spins)
|
|
||||||
{
|
|
||||||
lock->contended++;
|
|
||||||
if (lock->maxspins < spins)
|
|
||||||
{
|
|
||||||
lock->maxspins = spins;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lock->acquired++;
|
|
||||||
lock->owner = thread_self();
|
|
||||||
atomic_add(&(lock->waiting), -1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool spinlock_acquire_nowait(const SPINLOCK* const_lock)
|
|
||||||
{
|
|
||||||
SPINLOCK* lock = (SPINLOCK*)const_lock;
|
|
||||||
if (__sync_lock_test_and_set(&(lock->lock), 1))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
lock->acquired++;
|
|
||||||
lock->owner = thread_self();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spinlock_release(const SPINLOCK* const_lock)
|
|
||||||
{
|
|
||||||
SPINLOCK* lock = (SPINLOCK*)const_lock;
|
|
||||||
mxb_assert(lock->lock != 0);
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
if (lock->waiting > lock->max_waiting)
|
|
||||||
{
|
|
||||||
lock->max_waiting = lock->waiting;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__sync_lock_release(&lock->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void spinlock_stats(const SPINLOCK* lock, void (* reporter)(void*, char*, int), void* hdl)
|
|
||||||
{
|
|
||||||
#if SPINLOCK_PROFILE
|
|
||||||
reporter(hdl, "Spinlock acquired", lock->acquired);
|
|
||||||
if (lock->acquired)
|
|
||||||
{
|
|
||||||
reporter(hdl, "Total no. of spins", lock->spins);
|
|
||||||
if (lock->acquired)
|
|
||||||
{
|
|
||||||
reporter(hdl, "Average no. of spins (overall)", lock->spins / lock->acquired);
|
|
||||||
}
|
|
||||||
if (lock->contended)
|
|
||||||
{
|
|
||||||
reporter(hdl, "Average no. of spins (when contended)", lock->spins / lock->contended);
|
|
||||||
}
|
|
||||||
reporter(hdl, "Maximum no. of spins", lock->maxspins);
|
|
||||||
reporter(hdl, "Maximim no. of blocked threads", lock->max_waiting);
|
|
||||||
reporter(hdl, "Contended locks", lock->contended);
|
|
||||||
if (lock->acquired)
|
|
||||||
{
|
|
||||||
reporter(hdl, "Contention percentage", (lock->contended * 100) / lock->acquired);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@ -19,7 +19,6 @@ add_executable(test_modutil test_modutil.cc)
|
|||||||
add_executable(test_poll test_poll.cc)
|
add_executable(test_poll test_poll.cc)
|
||||||
add_executable(test_server test_server.cc)
|
add_executable(test_server test_server.cc)
|
||||||
add_executable(test_service test_service.cc)
|
add_executable(test_service test_service.cc)
|
||||||
add_executable(test_spinlock test_spinlock.cc)
|
|
||||||
add_executable(test_trxcompare test_trxcompare.cc ../../../query_classifier/test/testreader.cc)
|
add_executable(test_trxcompare test_trxcompare.cc ../../../query_classifier/test/testreader.cc)
|
||||||
add_executable(test_trxtracking test_trxtracking.cc)
|
add_executable(test_trxtracking test_trxtracking.cc)
|
||||||
add_executable(test_users test_users.cc)
|
add_executable(test_users test_users.cc)
|
||||||
@ -47,7 +46,6 @@ target_link_libraries(test_modutil maxscale-common)
|
|||||||
target_link_libraries(test_poll maxscale-common)
|
target_link_libraries(test_poll maxscale-common)
|
||||||
target_link_libraries(test_server maxscale-common)
|
target_link_libraries(test_server maxscale-common)
|
||||||
target_link_libraries(test_service maxscale-common)
|
target_link_libraries(test_service maxscale-common)
|
||||||
target_link_libraries(test_spinlock maxscale-common)
|
|
||||||
target_link_libraries(test_trxcompare maxscale-common)
|
target_link_libraries(test_trxcompare maxscale-common)
|
||||||
target_link_libraries(test_trxtracking maxscale-common)
|
target_link_libraries(test_trxtracking maxscale-common)
|
||||||
target_link_libraries(test_users maxscale-common)
|
target_link_libraries(test_users maxscale-common)
|
||||||
@ -74,7 +72,6 @@ add_test(test_modutil test_modutil)
|
|||||||
add_test(test_poll test_poll)
|
add_test(test_poll test_poll)
|
||||||
add_test(test_server test_server)
|
add_test(test_server test_server)
|
||||||
add_test(test_service test_service)
|
add_test(test_service test_service)
|
||||||
add_test(test_spinlock test_spinlock)
|
|
||||||
add_test(test_trxcompare_create test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/create.test)
|
add_test(test_trxcompare_create test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/create.test)
|
||||||
add_test(test_trxcompare_delete test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/delete.test)
|
add_test(test_trxcompare_delete test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/delete.test)
|
||||||
add_test(test_trxcompare_insert test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/insert.test)
|
add_test(test_trxcompare_insert test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/insert.test)
|
||||||
|
|||||||
@ -1,266 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
||||||
*
|
|
||||||
* Change Date: 2022-01-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2 or later of the General
|
|
||||||
* Public License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @verbatim
|
|
||||||
* Revision History
|
|
||||||
*
|
|
||||||
* Date Who Description
|
|
||||||
* 18/08-2014 Mark Riddoch Initial implementation
|
|
||||||
*
|
|
||||||
* @endverbatim
|
|
||||||
*/
|
|
||||||
|
|
||||||
// To ensure that ss_info_assert asserts also when builing in non-debug mode.
|
|
||||||
#if !defined (SS_DEBUG)
|
|
||||||
#define SS_DEBUG
|
|
||||||
#endif
|
|
||||||
#if defined (NDEBUG)
|
|
||||||
#undef NDEBUG
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <maxscale/spinlock.h>
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* test1 spinlock_acquire_nowait tests
|
|
||||||
*
|
|
||||||
* Test that spinlock_acquire_nowait returns false if the spinlock
|
|
||||||
* is already taken.
|
|
||||||
*
|
|
||||||
* Test that spinlock_acquire_nowait returns true if the spinlock
|
|
||||||
* is not taken.
|
|
||||||
*
|
|
||||||
* Test that spinlock_acquire_nowait does hold the spinlock.
|
|
||||||
*/
|
|
||||||
static int test1()
|
|
||||||
{
|
|
||||||
SPINLOCK lck;
|
|
||||||
|
|
||||||
spinlock_init(&lck);
|
|
||||||
spinlock_acquire(&lck);
|
|
||||||
if (spinlock_acquire_nowait(&lck))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "spinlock_acquire_nowait: test 1.1 failed.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
spinlock_release(&lck);
|
|
||||||
if (!spinlock_acquire_nowait(&lck))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "spinlock_acquire_nowait: test 1.2 failed.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (spinlock_acquire_nowait(&lck))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "spinlock_acquire_nowait: test 1.3 failed.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
spinlock_release(&lck);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int acquire_time;
|
|
||||||
|
|
||||||
static void test2_helper(void* data)
|
|
||||||
{
|
|
||||||
SPINLOCK* lck = (SPINLOCK*)data;
|
|
||||||
unsigned long t1 = time(0);
|
|
||||||
|
|
||||||
spinlock_acquire(lck);
|
|
||||||
acquire_time = time(0) - t1;
|
|
||||||
spinlock_release(lck);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* test2 spinlock_acquire tests
|
|
||||||
*
|
|
||||||
* Check that spinlock correctly blocks another thread whilst the spinlock
|
|
||||||
* is held.
|
|
||||||
*
|
|
||||||
* Take out a lock.
|
|
||||||
* Start a second thread to take the same lock
|
|
||||||
* sleep for 10 seconds
|
|
||||||
* release lock
|
|
||||||
* verify that second thread took at least 8 seconds to obtain the lock
|
|
||||||
*/
|
|
||||||
static int test2()
|
|
||||||
{
|
|
||||||
SPINLOCK lck;
|
|
||||||
std::thread handle;
|
|
||||||
struct timespec sleeptime;
|
|
||||||
|
|
||||||
sleeptime.tv_sec = 10;
|
|
||||||
sleeptime.tv_nsec = 0;
|
|
||||||
|
|
||||||
acquire_time = 0;
|
|
||||||
spinlock_init(&lck);
|
|
||||||
spinlock_acquire(&lck);
|
|
||||||
handle = std::thread(test2_helper, (void*)&lck);
|
|
||||||
nanosleep(&sleeptime, NULL);
|
|
||||||
spinlock_release(&lck);
|
|
||||||
handle.join();
|
|
||||||
|
|
||||||
if (acquire_time < 8)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "spinlock: test 2 failed.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* test3 spinlock_acquire tests process bound threads
|
|
||||||
*
|
|
||||||
* Check that spinlock correctly blocks all other threads whilst the spinlock
|
|
||||||
* is held.
|
|
||||||
*
|
|
||||||
* Start multiple threads that obtain spinlock and run process bound
|
|
||||||
*/
|
|
||||||
#define THREADS 5
|
|
||||||
#define ITERATIONS 50000
|
|
||||||
#define PROCESS_LOOP 10000
|
|
||||||
#define SECONDS 15
|
|
||||||
#define NANOTIME 100000
|
|
||||||
|
|
||||||
static int times_run, failures;
|
|
||||||
static volatile int active;
|
|
||||||
static int threadrun[THREADS];
|
|
||||||
static int nowait[THREADS];
|
|
||||||
static SPINLOCK lck;
|
|
||||||
static void test3_helper(void* data)
|
|
||||||
{
|
|
||||||
// SPINLOCK *lck = (SPINLOCK *)data;
|
|
||||||
int i;
|
|
||||||
int n = *(int*)data;
|
|
||||||
time_t rawtime;
|
|
||||||
|
|
||||||
#if defined (ADD_SOME_NANOSLEEP)
|
|
||||||
struct timespec sleeptime;
|
|
||||||
|
|
||||||
sleeptime.tv_sec = 0;
|
|
||||||
sleeptime.tv_nsec = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (spinlock_acquire_nowait(&lck))
|
|
||||||
{
|
|
||||||
nowait[n]++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spinlock_acquire(&lck);
|
|
||||||
}
|
|
||||||
if (times_run++ > ITERATIONS)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
threadrun[n]++;
|
|
||||||
/*
|
|
||||||
* if (99 == (times_run % 100)) {
|
|
||||||
* time ( &rawtime );
|
|
||||||
* fprintf(stderr, "%s Done %d iterations of test, in thread %d.\n", asctime (localtime ( &rawtime
|
|
||||||
* )), times_run, n);
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
if (0 != active)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "spinlock: test 3 failed with active non-zero after lock obtained.\n");
|
|
||||||
failures++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
active = 1;
|
|
||||||
for (i = 0; i < PROCESS_LOOP; i++)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
active = 0;
|
|
||||||
spinlock_release(&lck);
|
|
||||||
for (i = 0; i < (4 * PROCESS_LOOP); i++)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#if defined (ADD_SOME_NANOSLEEP)
|
|
||||||
nanosleep(&sleeptime, NULL);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
spinlock_release(&lck);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int test3()
|
|
||||||
{
|
|
||||||
// SPINLOCK lck;
|
|
||||||
std::thread handle[THREADS];
|
|
||||||
int i;
|
|
||||||
int tnum[THREADS];
|
|
||||||
time_t rawtime;
|
|
||||||
|
|
||||||
times_run = 0;
|
|
||||||
active = 0;
|
|
||||||
failures = 0;
|
|
||||||
spinlock_init(&lck);
|
|
||||||
time (&rawtime);
|
|
||||||
fprintf(stderr, "%s Starting %d threads.\n", asctime (localtime (&rawtime)), THREADS);
|
|
||||||
for (i = 0; i < THREADS; i++)
|
|
||||||
{
|
|
||||||
threadrun[i] = 0;
|
|
||||||
tnum[i] = i;
|
|
||||||
handle[i] = std::thread(test3_helper, &tnum[i]);
|
|
||||||
}
|
|
||||||
for (i = 0; i < THREADS; i++)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"spinlock_test 3 thread %d ran %d times, no wait %d times before waits.\n",
|
|
||||||
i,
|
|
||||||
threadrun[i],
|
|
||||||
nowait[i]);
|
|
||||||
}
|
|
||||||
for (i = 0; i < THREADS; i++)
|
|
||||||
{
|
|
||||||
time (&rawtime);
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s spinlock_test 3 finished sleeps, about to wait for thread %d.\n",
|
|
||||||
asctime (localtime (&rawtime)),
|
|
||||||
i);
|
|
||||||
handle[i].join();
|
|
||||||
}
|
|
||||||
for (i = 0; i < THREADS; i++)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"spinlock_test 3 thread %d ran %d times, no wait %d times.\n",
|
|
||||||
i,
|
|
||||||
threadrun[i],
|
|
||||||
nowait[i]);
|
|
||||||
}
|
|
||||||
time (&rawtime);
|
|
||||||
fprintf(stderr, "%s spinlock_test 3 completed, %d failures.\n", asctime (localtime (&rawtime)), failures);
|
|
||||||
return 0 == failures ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
result += test1();
|
|
||||||
result += test2();
|
|
||||||
result += test3();
|
|
||||||
|
|
||||||
exit(result);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user