    // Copyright (C) 2003  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_THREADS_KERNEl_2_
    #define DLIB_THREADS_KERNEl_2_

    #ifdef DLIB_ISO_CPP_ONLY
    #error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
    #endif

    #include "threads_kernel_abstract.h"
    #include <pthread.h>
    #include <errno.h>
    #include <sys/time.h>
    #include "../algs.h"

    namespace dlib
    {

    // ----------------------------------------------------------------------------------------

        typedef pthread_t thread_id_type;

        inline thread_id_type get_thread_id (
        )
        {
            return pthread_self();
        }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
        // mutex object
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        // forward declaration of signaler
        class signaler;

        class mutex
        {
            // give signaler access to hMutex
            friend class signaler;
        public:

            mutex (
            )
            {
                if (pthread_mutex_init(&myMutex,0))
                {
                    throw dlib::thread_error(ECREATE_MUTEX,
            "in function mutex::mutex() an error occurred making the mutex"
                    );
                }
            }

            ~mutex (
            ) { pthread_mutex_destroy(&myMutex); }

            void lock (
            ) const { pthread_mutex_lock(&myMutex); }

            void unlock (
            ) const { pthread_mutex_unlock(&myMutex); }

        private:

            mutable pthread_mutex_t myMutex;

            // restricted functions
            mutex(mutex&);        // copy constructor
            mutex& operator=(mutex&);    // assignement opertor
        };

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
        // signaler object
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        class signaler
        {

        public:

            signaler (
                const mutex& assoc_mutex
            ) :
                associated_mutex(&assoc_mutex.myMutex),
                m(assoc_mutex)
            {
                if (pthread_cond_init(&cond,0))
                {
                    throw dlib::thread_error(ECREATE_SIGNALER,
            "in function signaler::signaler() an error occurred making the signaler"
                    );
                }
            }

            ~signaler (
            ) { pthread_cond_destroy(&cond); }

            void wait (
            ) const
            {
                pthread_cond_wait(&cond,associated_mutex);
            }

            bool wait_or_timeout (
                unsigned long milliseconds
            ) const
            {
                timespec time_to_wait;

                timeval curtime;
                gettimeofday(&curtime,0);

                // get the time and adjust the timespec object by the appropriate amount
                time_to_wait.tv_sec = milliseconds/1000 + curtime.tv_sec;
                time_to_wait.tv_nsec = curtime.tv_usec;
                time_to_wait.tv_nsec *= 1000;
                time_to_wait.tv_nsec += (milliseconds%1000)*1000000;

                time_to_wait.tv_sec += time_to_wait.tv_nsec/1000000000;
                time_to_wait.tv_nsec = time_to_wait.tv_nsec%1000000000;

                if ( pthread_cond_timedwait(&cond,associated_mutex,&time_to_wait) == ETIMEDOUT)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }

            void signal (
            ) const { pthread_cond_signal(&cond); }

            void broadcast (
            ) const { pthread_cond_broadcast(&cond); }

            const mutex& get_mutex (
            ) const { return m; }

        private:

            pthread_mutex_t* const associated_mutex;
            mutable pthread_cond_t  cond;
            const mutex& m;

            // restricted functions
            signaler(signaler&);        // copy constructor
            signaler& operator=(signaler&);    // assignement opertor
        };

    // ----------------------------------------------------------------------------------------

        namespace threads_kernel_shared_helpers
        {
            bool spawn_thread (
                void (*funct)(void*),
                void* param
            );
            /*!
                is identical to create_new_thread() but just doesn't use any thread pooling.
            !*/
        }

    // ----------------------------------------------------------------------------------------

    }

    #include "threads_kernel_shared.h"

    #ifdef NO_MAKEFILE
    #include "threads_kernel_2.cpp"
    #endif

    #endif // DLIB_THREADS_KERNEl_2_