blob: 88bce011ba89065c546da399d3535a7015cb38bc [file] [log] [blame]
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER
#define BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
#include <cassert>
#include "util.hpp"
namespace boost { namespace interprocess { namespace test {
template<typename SM>
void plain_exclusive(void *arg, SM &sm)
{
data<SM> *pdata = static_cast<data<SM>*>(arg);
boost::interprocess::scoped_lock<SM> l(sm);
boost::thread::sleep(xsecs(3*BaseSeconds));
shared_val += 10;
pdata->m_value = shared_val;
}
template<typename SM>
void plain_shared(void *arg, SM &sm)
{
data<SM> *pdata = static_cast<data<SM>*>(arg);
boost::interprocess::sharable_lock<SM> l(sm);
if(pdata->m_secs){
boost::thread::sleep(xsecs(pdata->m_secs*BaseSeconds));
}
pdata->m_value = shared_val;
}
template<typename SM>
void try_exclusive(void *arg, SM &sm)
{
data<SM> *pdata = static_cast<data<SM>*>(arg);
boost::interprocess::scoped_lock<SM> l(sm, boost::interprocess::defer_lock);
if (l.try_lock()){
boost::thread::sleep(xsecs(3*BaseSeconds));
shared_val += 10;
pdata->m_value = shared_val;
}
}
template<typename SM>
void try_shared(void *arg, SM &sm)
{
data<SM> *pdata = static_cast<data<SM>*>(arg);
boost::interprocess::sharable_lock<SM> l(sm, boost::interprocess::defer_lock);
if (l.try_lock()){
if(pdata->m_secs){
boost::thread::sleep(xsecs(pdata->m_secs*BaseSeconds));
}
pdata->m_value = shared_val;
}
}
template<typename SM>
void timed_exclusive(void *arg, SM &sm)
{
data<SM> *pdata = static_cast<data<SM>*>(arg);
boost::posix_time::ptime pt(delay(pdata->m_secs));
boost::interprocess::scoped_lock<SM>
l (sm, boost::interprocess::defer_lock);
if (l.timed_lock(pt)){
boost::thread::sleep(xsecs(3*BaseSeconds));
shared_val += 10;
pdata->m_value = shared_val;
}
}
template<typename SM>
void timed_shared(void *arg, SM &sm)
{
data<SM> *pdata = static_cast<data<SM>*>(arg);
boost::posix_time::ptime pt(delay(pdata->m_secs));
boost::interprocess::sharable_lock<SM>
l(sm, boost::interprocess::defer_lock);
if (l.timed_lock(pt)){
if(pdata->m_secs){
boost::thread::sleep(xsecs(pdata->m_secs*BaseSeconds));
}
pdata->m_value = shared_val;
}
}
template<bool SameObject, typename SM>
void test_plain_sharable_mutex()
{
{
shared_val = 0;
SM m1, m2, m3, m4;
SM *pm1, *pm2, *pm3, *pm4;
if(SameObject){
pm1 = pm2 = pm3 = pm4 = &m1;
}
else{
pm1 = &m1;
pm2 = &m2;
pm3 = &m3;
pm4 = &m4;
}
data<SM> s1(1);
data<SM> s2(2);
data<SM> e1(1);
data<SM> e2(2);
// Writer one launches, holds the lock for 3*BaseSeconds seconds.
boost::thread tw1(thread_adapter<SM>(plain_exclusive, &e1, *pm1));
// Writer two launches, tries to grab the lock, "clearly"
// after Writer one will already be holding it.
boost::thread::sleep(xsecs(1*BaseSeconds));
boost::thread tw2(thread_adapter<SM>(plain_exclusive, &e2, *pm2));
// Reader one launches, "clearly" after writer two, and "clearly"
// while writer 1 still holds the lock
boost::thread::sleep(xsecs(1*BaseSeconds));
boost::thread thr1(thread_adapter<SM>(plain_shared,&s1, *pm3));
boost::thread thr2(thread_adapter<SM>(plain_shared,&s2, *pm4));
thr2.join();
thr1.join();
tw2.join();
tw1.join();
//We can only assure that the writer will be first
assert(e1.m_value == 10);
//A that we will execute all
assert(s1.m_value == 20 || s2.m_value == 20 || e2.m_value == 20);
}
{
shared_val = 0;
SM m1, m2, m3, m4;
SM *pm1, *pm2, *pm3, *pm4;
if(SameObject){
pm1 = pm2 = pm3 = pm4 = &m1;
}
else{
pm1 = &m1;
pm2 = &m2;
pm3 = &m3;
pm4 = &m4;
}
data<SM> s1(1, 3);
data<SM> s2(2, 3);
data<SM> e1(1);
data<SM> e2(2);
//We launch 2 readers, that will block for 3*BaseTime seconds
boost::thread thr1(thread_adapter<SM>(plain_shared,&s1,*pm1));
boost::thread thr2(thread_adapter<SM>(plain_shared,&s2,*pm2));
//Make sure they try to hold the sharable lock
boost::thread::sleep(xsecs(1*BaseSeconds));
// We launch two writers, that should block until the readers end
boost::thread tw1(thread_adapter<SM>(plain_exclusive,&e1,*pm3));
boost::thread tw2(thread_adapter<SM>(plain_exclusive,&e2,*pm4));
thr2.join();
thr1.join();
tw2.join();
tw1.join();
//We can only assure that the shared will finish first...
assert(s1.m_value == 0 || s2.m_value == 0);
//...and writers will be mutually excluded after readers
assert((e1.m_value == 10 && e2.m_value == 20) ||
(e1.m_value == 20 && e2.m_value == 10) );
}
}
template<bool SameObject, typename SM>
void test_try_sharable_mutex()
{
SM m1, m2, m3;
SM *pm1, *pm2, *pm3;
if(SameObject){
pm1 = pm2 = pm3 = &m1;
}
else{
pm1 = &m1;
pm2 = &m2;
pm3 = &m3;
}
data<SM> s1(1);
data<SM> e1(2);
data<SM> e2(3);
// We start with some specialized tests for "try" behavior
shared_val = 0;
// Writer one launches, holds the lock for 3*BaseSeconds seconds.
boost::thread tw1(thread_adapter<SM>(try_exclusive,&e1,*pm1));
// Reader one launches, "clearly" after writer #1 holds the lock
// and before it releases the lock.
boost::thread::sleep(xsecs(1*BaseSeconds));
boost::thread thr1(thread_adapter<SM>(try_shared,&s1,*pm2));
// Writer two launches in the same timeframe.
boost::thread tw2(thread_adapter<SM>(try_exclusive,&e2,*pm3));
tw2.join();
thr1.join();
tw1.join();
assert(e1.m_value == 10);
assert(s1.m_value == -1); // Try would return w/o waiting
assert(e2.m_value == -1); // Try would return w/o waiting
}
template<bool SameObject, typename SM>
void test_timed_sharable_mutex()
{
SM m1, m2, m3, m4;
SM *pm1, *pm2, *pm3, *pm4;
if(SameObject){
pm1 = pm2 = pm3 = pm4 = &m1;
}
else{
pm1 = &m1;
pm2 = &m2;
pm3 = &m3;
pm4 = &m4;
}
data<SM> s1(1,1*BaseSeconds);
data<SM> s2(2,3*BaseSeconds);
data<SM> e1(3,3*BaseSeconds);
data<SM> e2(4,1*BaseSeconds);
// We begin with some specialized tests for "timed" behavior
shared_val = 0;
// Writer one will hold the lock for 3*BaseSeconds seconds.
boost::thread tw1(thread_adapter<SM>(timed_exclusive,&e1,*pm1));
boost::thread::sleep(xsecs(1*BaseSeconds));
// Writer two will "clearly" try for the lock after the readers
// have tried for it. Writer will wait up 1*BaseSeconds seconds for the lock.
// This write will fail.
boost::thread tw2(thread_adapter<SM>(timed_exclusive,&e2,*pm2));
// Readers one and two will "clearly" try for the lock after writer
// one already holds it. 1st reader will wait 1*BaseSeconds seconds, and will fail
// to get the lock. 2nd reader will wait 3*BaseSeconds seconds, and will get
// the lock.
boost::thread thr1(thread_adapter<SM>(timed_shared,&s1,*pm3));
boost::thread thr2(thread_adapter<SM>(timed_shared,&s2,*pm4));
tw1.join();
thr1.join();
thr2.join();
tw2.join();
assert(e1.m_value == 10);
assert(s1.m_value == -1);
assert(s2.m_value == 10);
assert(e2.m_value == -1);
}
template<bool SameObject, typename SM>
void test_all_sharable_mutex()
{
std::cout << "test_plain_sharable_mutex<" << SameObject << ", " << typeid(SM).name() << ">" << std::endl;
test_plain_sharable_mutex<SameObject, SM>();
std::cout << "test_try_sharable_mutex<" << SameObject << ", " << typeid(SM).name() << ">" << std::endl;
test_try_sharable_mutex<SameObject, SM>();
std::cout << "test_timed_sharable_mutex<" << SameObject << ", " << typeid(SM).name() << ">" << std::endl;
test_timed_sharable_mutex<SameObject, SM>();
}
}}} //namespace boost { namespace interprocess { namespace test {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER