/*
* This file is part of the Omni C++ framework
*
* Copyright (c) 2016, Zeriph Enterprises, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of Zeriph, Zeriph Enterprises, LLC, nor the names
* of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(OMNI_BASIC_THREAD_HPP)
#define OMNI_BASIC_THREAD_HPP 1
#include <omni/defs/class_macros.hpp>
#include <omni/types/thread_t.hpp>
#include <omni/sync/spin.hpp>
#include <omni/sync/basic_lock.hpp>
#include <map>
namespace omni {
namespace sync {
/** Represents an unmanaged system thread object. */
class basic_thread
{
public:
// Where a constructor specifies a delegate method, unless user specified, the default start type is NOW
basic_thread();
basic_thread(
const omni::sync::basic_thread& cp);
explicit basic_thread(
const omni::sync::thread_flags& ops);
explicit basic_thread(std::size_t max_stack_sz);
explicit basic_thread(
const omni::sync::thread_start& mthd);
explicit basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd);
basic_thread(
const omni::sync::thread_t& tid,
const omni::sync::thread_handle_t& h);
basic_thread(
const omni::sync::thread_start& mthd,
omni::sync::thread_start_type_t st);
basic_thread(
const omni::sync::thread_start& mthd,
std::size_t max_stack_sz);
basic_thread(
const omni::sync::thread_start& mthd,
std::size_t max_stack_sz,
omni::sync::thread_start_type_t st);
basic_thread(
const omni::sync::thread_start& mthd,
omni::sync::thread_option_t op,
omni::sync::thread_union_t val);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
omni::generic_ptr args);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
omni::sync::thread_start_type_t st);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
omni::sync::thread_start_type_t st,
omni::generic_ptr args);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
std::size_t max_stack_sz);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
std::size_t max_stack_sz,
omni::generic_ptr args);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
std::size_t max_stack_sz,
omni::sync::thread_start_type_t st);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
std::size_t max_stack_sz,
omni::sync::thread_start_type_t st,
omni::generic_ptr args);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
omni::sync::thread_option_t op,
omni::sync::thread_union_t val);
basic_thread(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd,
omni::generic_ptr args,
omni::sync::thread_option_t op,
omni::sync::thread_union_t val);
~basic_thread();
void bind(
const @parameterized_thread_start.html">omni::sync::parameterized_thread_start& mthd);
void bind(
const omni::sync::thread_start& mthd);
void detach();
void detach(
bool allow_rejoin);
const omni::sync::thread_union_t get_option(
omni::sync::thread_option_t op)
const;
omni::sync::thread_flags options()
const;
const omni::sync::thread_handle_t handle()
const;
const omni::sync::thread_t id()
const;
bool is_alive()
const;
bool is_bound()
const;
bool is_parameter_bound()
const;
bool is_detached()
const;
bool join();
// default of infinite timeout
bool join(
unsigned long timeout);
//TODO: add bool join(const omni::timespan& t); when omni::timespan complete
bool kill();
// Terminate 'immediately'
omni::sync::thread_state_t status()
const;
void start();
void start(
omni::generic_ptr args);
void set_option(
omni::sync::thread_option_t op,
omni::sync::thread_union_t val);
void set_options(
unsigned char op,
bool val);
void set_options(
const omni::sync::thread_flags& ops);
void swap(omni::sync::basic_thread& other);
void unbind();
omni::sync::basic_thread&
operator=(
const omni::sync::basic_thread& other);
bool operator==(
const omni::sync::basic_thread& other)
const;
bool operator!=(
const omni::sync::basic_thread& other)
const;
// TODO: bool is_threadpool_thread() const;
#if defined(OMNI_NON_PORTABLE)
omni::sync::thread_priority_t priority()
const;
void set_priority(
omni::sync::thread_priority_t p);
#endif
OMNI_MEMBERS_FW(omni::sync::basic_thread)
// disposing,name,type(),hash()
inline static const omni::sync::basic_thread current()
{
return omni::sync::basic_thread(
omni::sync::thread_id(),
omni::sync::thread_handle());
}
private:
// Methods
void _chkmthd();
void _close_handle(
bool allow_rejoin);
void _hreset(
bool force,
bool allow_rejoin);
bool _hvalid()
const;
bool _state_running()
const;
void _state_machine(
const omni::sync::thread_t tid);
void _set_context(
const omni::sync::basic_thread& t2);
#if defined(OMNI_NON_PORTABLE)
void _set_prio();
#endif
// Members
#if defined(OMNI_TYPE_INFO)
omni::type<omni::sync::basic_thread> m_type;
#endif
#if defined(OMNI_SAFE_BASIC_THREAD)
mutable omni::sync::basic_lock m_mtx;
#endif
/** The arguments passed to the thread */
omni::generic_ptr m_args;
/** The delegate invoked on the thread when started */
@parameterized_thread_start.html">omni::sync::parameterized_thread_start* m_pmthd;
omni::sync::thread_start* m_mthd;
/** Wait object used to signal when the thread has started */
omni::sync::safe_spin_wait* m_switch;
/** The underlying thread ID type */
omni::sync::thread_t m_tid;
/** The underlying thread handle type */
omni::sync::thread_handle_t m_thread;
/** The underlying thread options */
omni::sync::thread_flags m_ops;
/** The current state of the thread */
omni::sync::thread_state_t m_state;
#if defined(OMNI_NON_PORTABLE)
/** The threads priority */
omni::sync::thread_priority_t m_priority;
#endif
/** If join has been called, don't detach */
volatile bool m_isjoined;
static OMNI_THREAD_FNPTR_T OMNI_THREAD_CALL_T _start(
void* param);
/**
* This class is an internal thread manager not intended to be used anywhere but here.
* It's used to avoid the static init order fiasco (via the static instance function).
* It's private to avoid external use as well to allow it access to the private functions.
*/
class manager
{
public:
manager() : m_lock(), m_threads() {}
~manager() {}
void push_back(
omni::sync::thread_t tid, omni::sync::basic_thread& bthread);
void pop_back(
omni::sync::thread_t tid);
void remove(
omni::sync::thread_t tid);
static manager& instance()
{
static omni::sync::basic_thread::manager* ret =
new omni::sync::basic_thread::manager();
return *ret;
}
private:
typedef std::map<
omni::sync::thread_t, omni::sync::basic_thread*> thread_map;
omni::sync::basic_lock m_lock;
thread_map m_threads;
manager(
const manager& cp);
// = delete;
manager&
operator=(
const manager& cp);
// = delete;
};
};
inline void swap(omni::sync::basic_thread& ot1, omni::sync::basic_thread& ot2)
{
ot1.swap(ot2);
}
}
}
// namespace omni
namespace std {
inline void swap(omni::sync::basic_thread& ot1, omni::sync::basic_thread& ot2)
{
ot1.swap(ot2);
}
}
#include <omni/sync/basic_thread_allocate.hpp>
#endif // OMNI_BASIC_THREAD_HPP