bool dxThreadingThreadPool::InitializeThreads(size_t thread_count, size_t stack_size, unsigned int ode_data_allocate_flags)
{
    dIASSERT(m_thread_infos == NULL);

    bool result = false;

    bool wait_event_allocated = false;

    dxThreadPoolThreadInfo *thread_infos = NULL;
    bool thread_infos_allocated = false;

    do
    {
        if (!m_ready_wait_event.InitializeObject(false, false))
        {
            break;
        }

        wait_event_allocated = true;

        thread_infos = (dxThreadPoolThreadInfo *)dAlloc(thread_count * sizeof(dxThreadPoolThreadInfo));
        if (thread_infos == NULL)
        {
            break;
        }

        thread_infos_allocated = true;

        if (!InitializeIndividualThreadInfos(thread_infos, thread_count, stack_size, ode_data_allocate_flags))
        {
            break;
        }

        m_thread_infos = thread_infos;
        m_thread_count = thread_count;
        result = true;
    }
    while (false);

    if (!result)
    {
        if (wait_event_allocated)
        {
            if (thread_infos_allocated)
            {
                dFree(thread_infos, thread_count * sizeof(dxThreadPoolThreadInfo));
            }

            m_ready_wait_event.FinalizeObject();
        }
    }

    return result;
}
void dxThreadPoolThreadInfo::Finalize()
{
    if (m_thread_allocated)
    {
        ExecuteThreadCommand(dxTHREAD_COMMAND_EXIT, NULL, false);

        WaitAndCloseThreadHandle(m_thread_handle);
        m_thread_allocated = false;

        m_command_event.FinalizeObject();
        m_acknowledgement_event.FinalizeObject();
    }
}
void dxThreadPoolThreadInfo::Finalize()
{
    HANDLE thread_handle = m_thread_handle;
    if (thread_handle != NULL)
    {
        ExecuteThreadCommand(dxTHREAD_COMMAND_EXIT, NULL, false);

        WaitAndCloseThreadHandle(thread_handle);
        m_thread_handle = NULL;

        m_command_event.FinalizeObject();
        m_acknowledgement_event.FinalizeObject();
    }
}
void dxThreadPoolThreadInfo::RunCommandHandlingLoop()
{
    bool exit_requested = false;

    while (!exit_requested)
    {
        bool command_wait_result = m_command_event.WaitInfinitely();
        dICHECK(command_wait_result);

        const dxTHREADCOMMAND command_code = m_command_code;
        switch (command_code)
        {
            case dxTHREAD_COMMAND_EXIT:
            {
                m_acknowledgement_event.SetEvent();

                exit_requested = true;
                break;
            }

            default:
            {
                dIASSERT(false);
                // break; -- proceed to case dxTHREAD_COMMAND_NOOP
            }

            case dxTHREAD_COMMAND_NOOP:
            {
                m_acknowledgement_event.SetEvent();

                // Do nothing
                break;
            }

            case dxTHREAD_COMMAND_SERVE_IMPLEMENTATION:
            {
                const dxServeImplementationParams *serve_params = (const dxServeImplementationParams *)m_command_param;
                dThreadingImplementationID impl = serve_params->m_impl;
                dxEventObject *ready_wait_event = serve_params->m_ready_wait_event;

                m_acknowledgement_event.SetEvent();

                ThreadedServeImplementation(impl, ready_wait_event);
                break;
            }
        }
    }
}
void dxThreadPoolThreadInfo::ReportInitStatus(bool init_result)
{
    DWORD error_code;
    m_command_param = (void *)(size_t)(init_result ? ERROR_SUCCESS : ((error_code = GetLastError()) != ERROR_SUCCESS ? error_code : ERROR_INTERNAL_ERROR));

    m_acknowledgement_event.SetEvent();
}
void dxThreadPoolThreadInfo::ExecuteThreadCommand(dxTHREADCOMMAND command, void *param, bool wait_response)
{
    bool acknowledgement_wait_result = m_acknowledgement_event.WaitInfinitely();
    dICHECK(acknowledgement_wait_result);

    m_acknowledgement_event.ResetEvent();

    m_command_code = command;
    m_command_param = param;

    m_command_event.SetEvent();

    if (wait_response)
    {
        bool new_acknowledgement_wait_result = m_acknowledgement_event.WaitInfinitely();
        dICHECK(new_acknowledgement_wait_result);
    }
}
bool dxThreadPoolThreadInfo::WaitInitStatus()
{
    bool acknowledgement_wait_result = m_acknowledgement_event.WaitInfinitely();
    dICHECK(acknowledgement_wait_result);

    DWORD error_code = (DWORD)(size_t)m_command_param;

    bool init_status = error_code == ERROR_SUCCESS ? true : (SetLastError(error_code), false);
    return init_status;
}
bool dxThreadPoolThreadInfo::WaitInitStatus()
{
    bool acknowledgement_wait_result = m_acknowledgement_event.WaitInfinitely();
    dICHECK(acknowledgement_wait_result);

    int error_code = (int)(size_t)m_command_param;

    bool init_status = error_code == EOK ? true : ((errno = error_code), false);
    return init_status;
}
void dxThreadingThreadPool::ServeThreadingImplementation(dThreadingImplementationID impl)
{
    dxThreadPoolThreadInfo::dxServeImplementationParams params(impl, &m_ready_wait_event);

    dxThreadPoolThreadInfo *const infos_end = m_thread_infos + m_thread_count;
    for (dxThreadPoolThreadInfo *current_info = m_thread_infos; current_info != infos_end; ++current_info)
    {
        current_info->ExecuteThreadCommand(dxThreadPoolThreadInfo::dxTHREAD_COMMAND_SERVE_IMPLEMENTATION, &params, true);

        bool ready_wait_result = m_ready_wait_event.WaitInfinitely();
        dICHECK(ready_wait_result);
    }
}
void dxThreadingThreadPool::FinalizeThreads()
{
    dxThreadPoolThreadInfo *thread_infos = m_thread_infos;
    if (thread_infos != NULL)
    {
        size_t thread_count = m_thread_count;

        FinalizeIndividualThreadInfos(thread_infos, thread_count);
        dFree(thread_infos, thread_count * sizeof(dxThreadPoolThreadInfo));

        m_ready_wait_event.FinalizeObject();
    }
}
bool dxThreadPoolThreadInfo::Initialize(size_t stack_size, unsigned int ode_data_allocate_flags)
{
    bool result = false;

    bool command_event_allocated = false, acknowledgement_event_allocated = false;

    HANDLE thread_handle = NULL;

    do 
    {
        if (stack_size > THREAD_STACK_MAX)
        {
            SetLastError(ERROR_INVALID_PARAMETER);
            break;
        }

        if (!m_command_event.InitializeObject(false, false))
        {
            break;
        }

        command_event_allocated = true;

        if (!m_acknowledgement_event.InitializeObject(true, false))
        {
            break;
        }

        acknowledgement_event_allocated = true;

        m_ode_data_allocate_flags = ode_data_allocate_flags;

        thread_handle = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, &ThreadProcedure_Callback, (void *)this, 0, NULL);
        if (thread_handle == NULL) // Not a bug!!! _beginthreadex() returns NULL on failure
        {
            break;
        }

        // It is OK to alter priority for thread without creating it in suspended state as
        // it is anyway going to be waited for (waited for its init result) and 
        // will not be issues commands until after that.
        int own_priority = GetThreadPriority(GetCurrentThread());
        if (own_priority != THREAD_PRIORITY_ERROR_RETURN)
        {
            if (!SetThreadPriority(thread_handle, own_priority))
            {
                // own_priority = THREAD_PRIORITY_ERROR_RETURN; -- Well, if priority inheritance fails - just ignore it :-/
            }
        }

        bool thread_init_result = WaitInitStatus();
        if (!thread_init_result)
        {
            DWORD error_save = GetLastError();
            WaitAndCloseThreadHandle(thread_handle);
            SetLastError(error_save);
            break;
        }

        m_thread_handle = thread_handle;
        result = true;
    }
    while (false);

    if (!result)
    {
        if (command_event_allocated)
        {
            if (acknowledgement_event_allocated)
            {
                m_acknowledgement_event.FinalizeObject();
            }

            m_command_event.FinalizeObject();
        }
    }

    return result;
}
void dxThreadPoolThreadInfo::ReportInitStatus(bool init_result)
{
    m_command_param = (void *)(size_t)(init_result ? EOK : ((errno != EOK) ? errno : EFAULT));

    m_acknowledgement_event.SetEvent();
}
bool dxThreadPoolThreadInfo::Initialize(size_t stack_size, unsigned int ode_data_allocate_flags)
{
    bool result = false;

    bool command_event_allocated = false, acknowledgement_event_allocated = false;

    do 
    {
        // -- There is no implicit limit on stack size in POSIX implementation
        // if (stack_size > ...)
        // {
        //   errno = EINVAL;
        //   break;
        // }

        if (!m_command_event.InitializeObject(false, false))
        {
            break;
        }

        command_event_allocated = true;

        if (!m_acknowledgement_event.InitializeObject(true, false))
        {
            break;
        }

        acknowledgement_event_allocated = true;

        m_ode_data_allocate_flags = ode_data_allocate_flags;

        pthread_attr_t thread_attr;
        if (!InitializeThreadAttributes(&thread_attr, stack_size))
        {
            break;
        }

        int thread_create_result = pthread_create(&m_thread_handle, &thread_attr, &ThreadProcedure_Callback, (void *)this);

        FinalizeThreadAttributes(&thread_attr);

        if (thread_create_result != EOK)
        {
            errno = thread_create_result;
            break;
        }

        bool thread_init_result = WaitInitStatus();
        if (!thread_init_result)
        {
            WaitAndCloseThreadHandle(m_thread_handle);
            break;
        }

        m_thread_allocated = true;
        result = true;
    }
    while (false);

    if (!result)
    {
        if (command_event_allocated)
        {
            if (acknowledgement_event_allocated)
            {
                m_acknowledgement_event.FinalizeObject();
            }

            m_command_event.FinalizeObject();
        }
    }

    return result;
}