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

    #include "threads_kernel.h"
    #include "rmutex_extension_abstract.h"

    namespace dlib
    {

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

        class rmutex
        {
            /*!
                INITIAL VALUE
                    count == 0
                    thread_id == 0

                CONVENTION
                    - count == lock_count()

                    - if (no thread currently has a lock on this mutex) then
                        - count == 0
                    - else
                        - count == the number of times the thread that owns this mutex has
                          called lock()
                        - thread_id == the id of this thread.
            !*/
        public:

            rmutex (
            ) : s(m),
                thread_id(0),
                count(0)
            {}

            ~rmutex (
            )
            {}

            unsigned long lock_count (
            ) const
            {
                return count;
            }

            void lock (
                unsigned long times = 1
            ) const
            {
                const thread_id_type current_thread_id = get_thread_id();
                m.lock();
                if (thread_id == current_thread_id)
                {
                    // we already own this mutex in this case
                    count += times;
                }
                else
                {
                    // wait for our turn to claim this rmutex
                    while (count != 0)
                        s.wait();

                    count = times;
                    thread_id = current_thread_id;
                }
                m.unlock();
            }

            void unlock (
                unsigned long times = 1
            ) const
            {
                const thread_id_type current_thread_id = get_thread_id();
                m.lock();
                if (thread_id == current_thread_id)
                {
                    if (count <= times)
                    {
                        count = 0;
                        s.signal();
                    }
                    else
                    {
                        count -= times;
                    }
                }
                m.unlock();
            }

        private:
            mutex m;
            signaler s;
            mutable thread_id_type thread_id;
            mutable unsigned long count;

            // restricted functions
            rmutex(rmutex&);        // copy constructor
            rmutex& operator=(rmutex&);    // assignment operator
        };

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

    }

    #endif // DLIB_RMUTEX_EXTENSIOn_