/*
* 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_RUNNABLE_HPP)
#define OMNI_RUNNABLE_HPP 1
#include <omni/sync/runnable.hpp>
#include <omni/types/thread_t.hpp>
#include <omni/sync/spin.hpp>
#if defined(OMNI_SAFE_RUNNABLE_THREAD)
#include <omni/sync/basic_lock.hpp>
#endif
namespace omni {
namespace sync {
/** Represents a managed over-ridable runnable thread object. */
class runnable_thread :
virtual public omni::sync::runnable
{
public:
/** Defines the thread changed event delegate signature */
typedef omni::delegate2<
void,
const omni::sync::runnable_thread&,
omni::sync::thread_state_t> state_delegate;
/** Defines the thread changed event delegate signature */
typedef omni::event2<
void,
const omni::sync::runnable_thread&,
omni::sync::thread_state_t> state_event;
// Methods
runnable_thread();
runnable_thread(
const omni::sync::runnable_thread& cp);
explicit runnable_thread(
const omni::sync::runnable& obj);
explicit runnable_thread(
const omni::sync::thread_flags& ops);
explicit runnable_thread(std::size_t max_stack_sz);
runnable_thread(
const omni::sync::runnable& obj, std::size_t max_stack_sz);
runnable_thread(
omni::sync::thread_option_t op,
omni::sync::thread_union_t val);
virtual ~runnable_thread();
void abort();
// End nicely
bool abort_join();
bool abort_join(
unsigned long timeout);
const omni::sync::thread_union_t get_option(
omni::sync::thread_option_t op)
const;
omni::sync::thread_flags get_options()
const;
const omni::sync::thread_handle_t handle()
const;
const omni::sync::thread_t id()
const;
bool is_alive()
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'
virtual void run(
omni::generic_ptr parm) {
OMNI_UNUSED(parm); }
// default empty run
bool reset();
bool restart();
bool restart(
omni::generic_ptr args);
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::runnable_thread& other);
omni::sync::runnable_thread&
operator=(
const omni::sync::runnable_thread& other);
using omni::sync::runnable::
operator==;
using omni::sync::runnable::
operator!=;
bool operator==(
const omni::sync::runnable_thread& other)
const;
bool operator!=(
const omni::sync::runnable_thread& other)
const;
#if defined(OMNI_NON_PORTABLE)
omni::sync::thread_priority_t priority()
const;
void set_priority(
omni::sync::thread_priority_t p);
#endif
/** Raised when the thread has changed state (running, stopped, etc) */
omni::sync::runnable_thread::state_event state_changed;
// disposing,name,type(),hash()
OMNI_MEMBERS_FW(omni::sync::runnable_thread)
protected:
virtual void state_update(
omni::sync::thread_state_t old_state) {
OMNI_UNUSED(old_state); }
private:
// Methods
void _close_handle();
void _hreset(
bool force =
false);
bool _hvalid()
const;
bool _state_running()
const;
void _state_changed(
omni::sync::thread_state_t nstate);
void _set_context(
const omni::sync::runnable_thread& t2);
#if defined(OMNI_NON_PORTABLE)
void _set_prio();
#endif
static OMNI_THREAD_FNPTR_T OMNI_THREAD_CALL_T _start(
void* param);
// Members
#if defined(OMNI_TYPE_INFO)
omni::type<omni::sync::runnable_thread> m_type;
#endif
#if defined(OMNI_SAFE_RUNNABLE_THREAD)
mutable omni::sync::basic_lock m_mtx;
#endif
/** The arguments passed to the thread */
omni::generic_ptr m_args;
/** The underlying interface that's called on thread run (if none assigned, then this->run()) */
omni::sync::runnable* m_iface;
/** Wait object used to signal when the thread has started */
omni::sync::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;
};
inline void swap(omni::sync::runnable_thread& ot1, omni::sync::runnable_thread& ot2)
{
ot1.swap(ot2);
}
}
// namespace sync
}
// namespace omni
namespace std {
inline void swap(omni::sync::runnable_thread& ot1, omni::sync::runnable_thread& ot2)
{
ot1.swap(ot2);
}
}
#endif // OMNI_RUNNABLE_HPP