├── LICENSE ├── README.md ├── cpp ├── consumer_thread.h ├── consumer_thread_impl.h ├── delegate │ ├── Delegate.h │ └── detail │ │ ├── DelegateN.h │ │ └── FastDelegate.h ├── dummylogger.h ├── lock_free_atomic_ops.h ├── lock_free_queue.h ├── lock_free_queue_impl.h ├── lock_free_queue_impl_multiple_producer.h ├── lock_free_queue_impl_single_producer.h ├── safe_queue.h ├── safe_queue_impl.h ├── singleton.h ├── test │ ├── Makefile │ ├── consumer_thread_test.cpp │ ├── lock_free_multiple_producers_q_test.cpp │ ├── lock_free_single_producer_q_test.cpp │ ├── safe_queue_test.cpp │ ├── singleton_test.cpp │ └── vtimer_test.cpp └── vtimer.h └── scripts ├── animated_graph.py ├── bash ├── .bash_aliases.sh ├── .vimrc └── command_hacks.sh ├── dat_parser.py ├── dummy_server.py ├── log_merger.py ├── ntp_mock.py ├── poormansprofiler.sh ├── random_udp.py └── rename_pictures.pl /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Faustino Frechilla 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | misc-playground 2 | =============== 3 | 4 | Miscellaneous scripts and things that dont merit their own repo. All under MIT License unless otherwise specified 5 | -------------------------------------------------------------------------------- /cpp/consumer_thread.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2009-2013 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file consumer_thread.h 23 | /// @brief This file contains the Consumer Thread class. 24 | /// 25 | /// Your compiler must have support for c++11. This is an example of how to 26 | /// compile an application that makes use of this consumer thread with gcc 4.8: 27 | /// $ g++ -g -O0 -Wall -std=c++11 -D_REENTRANT -c app.cpp 28 | /// $ g++ app.o -o app 29 | /// 30 | /// @author Faustino Frechilla 31 | /// @history 32 | /// Ref Who When What 33 | /// Faustino Frechilla 04-May-2009 Original development 34 | /// Faustino Frechilla 06-Jun-2013 Ported to c++11 35 | /// @endhistory 36 | /// 37 | // ============================================================================ 38 | 39 | #ifndef _CONSUMERTHREAD_H_ 40 | #define _CONSUMERTHREAD_H_ 41 | 42 | #include 43 | #include 44 | #include 45 | #include "safe_queue.h" 46 | 47 | template 48 | class ConsumerThread 49 | { 50 | public: 51 | /// @brief ConsumerThread constructor 52 | /// The queue size will be set to the safe queue's default 53 | /// @param a_consumeDelegate delegate to the function to be called per consumable 54 | /// @param a_initDelegate a delegate to the initialise function. It does nothing by default 55 | /// This function will get called from the context of the consumer thread 56 | ConsumerThread( 57 | std::function a_consumeDelegate, 58 | std::function a_initDelegate = std::bind(&ConsumerThread::DoNothing) ); 59 | /// @brief ConsumerThread constructor 60 | /// @param a_queueSize safe queue size 61 | /// @param a_consumeDelegate delegate to the function to be called per consumable 62 | /// @param a_initDelegate a delegate to the initialise function. It does nothing by default 63 | /// This function will get called from the context of the consumer thread 64 | ConsumerThread( 65 | std::size_t a_queueSize, 66 | std::function a_consumeDelegate, 67 | std::function a_initDelegate = std::bind(&ConsumerThread::DoNothing) ); 68 | 69 | virtual ~ConsumerThread(); 70 | 71 | /// @brief Tell the consumer thread to finish and wait until it does so 72 | /// suspends execution of the calling thread until the target thread terminates 73 | void Join(); 74 | 75 | /// @brief inserts data into the consumable queue to be processed by the ConsumerThread 76 | /// This call can block for a short period of time if another thread owns the lock that 77 | /// protects the queue. If the a_data can-t be pushed into the queue (it is full) the 78 | /// function will return as soon as possible 79 | /// @param a const reference to the element to insert into the queue 80 | /// @return true if the element was successfully inserted into the queue. False otherwise 81 | bool Produce(const T &a_data); 82 | 83 | /// @brief inserts data into the consumable queue to be processed by the ConsumerThread 84 | /// This call will block until a_data can be pushed into the queue 85 | /// @param a const reference to the element to insert into the queue 86 | void ProduceOrBlock(const T &a_data); 87 | 88 | private: 89 | /// the worker thread 90 | std::unique_ptr m_producerThread; 91 | 92 | /// flag to control if the execution of the thread must terminate 93 | std::atomic m_terminate; 94 | 95 | /// Delegate to the Consume function 96 | std::function m_consumeDelegate; 97 | 98 | /// Delegate to the Init function 99 | std::function m_initDelegate; 100 | 101 | /// The queue with the data to be processed 102 | SafeQueue m_consumableQueue; 103 | 104 | /// Creates the consumer thread calling to the necessary system functions 105 | void SpawnThread(); 106 | 107 | /// brief the routine that will be run by the consumer thread 108 | void ThreadRoutine(); 109 | 110 | /// @brief dummy function 111 | /// To be used when the user doesn't specify the init function 112 | static void DoNothing() {}; 113 | }; 114 | 115 | #include "consumer_thread_impl.h" 116 | 117 | #endif /* _CONSUMERTHREAD_H_ */ 118 | -------------------------------------------------------------------------------- /cpp/consumer_thread_impl.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2009-2013 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file consumer_thread_impl.h 23 | /// @brief This file contains the Consumer Thread class implementation. 24 | /// 25 | /// @author Faustino Frechilla 26 | /// @history 27 | /// Ref Who When What 28 | /// Faustino Frechilla 04-May-2009 Original development 29 | /// Faustino Frechilla 06-Jun-2013 Ported to c++11 30 | /// @endhistory 31 | /// 32 | // ============================================================================ 33 | 34 | #ifndef _CONSUMERTHREADIMPL_H_ 35 | #define _CONSUMERTHREADIMPL_H_ 36 | 37 | #include 38 | 39 | // wake up timeout. The consumer thread will wake up when the timeout is hit 40 | // when there is no data to consume to check if it has been told to finish 41 | #define CONSUMER_THREAD_TIMEOUT_USEC 1000 // (1ms = 1000us) 42 | 43 | template 44 | ConsumerThread::ConsumerThread(std::function a_consumeDelegate, std::function a_initDelegate) : 45 | m_terminate(false), 46 | m_consumeDelegate(a_consumeDelegate), 47 | m_initDelegate(a_initDelegate), 48 | m_consumableQueue() 49 | { 50 | SpawnThread(); 51 | } 52 | 53 | template 54 | ConsumerThread::ConsumerThread(std::size_t a_queueSize, std::function a_consumeDelegate, std::function a_initDelegate) : 55 | m_terminate(false), 56 | m_consumeDelegate(a_consumeDelegate), 57 | m_initDelegate(a_initDelegate), 58 | m_consumableQueue(a_queueSize) 59 | { 60 | SpawnThread(); 61 | } 62 | 63 | template 64 | ConsumerThread::~ConsumerThread() 65 | { 66 | if (m_producerThread.get()) 67 | { 68 | Join(); 69 | } 70 | } 71 | 72 | template 73 | void ConsumerThread::SpawnThread() 74 | { 75 | m_producerThread.reset( 76 | new std::thread(std::bind(&ConsumerThread::ThreadRoutine, this))); 77 | 78 | //m_producerThread->detach(); // the consumer thread will run as no joinable 79 | } 80 | 81 | template 82 | void ConsumerThread::Join() 83 | { 84 | m_terminate.store(true); 85 | 86 | m_producerThread->join(); 87 | m_producerThread.reset(); 88 | } 89 | 90 | template 91 | bool ConsumerThread::Produce(const T &a_data) 92 | { 93 | assert(m_producerThread.get() != 0); 94 | 95 | return m_consumableQueue.TryPush(a_data); 96 | } 97 | 98 | template 99 | void ConsumerThread::ProduceOrBlock(const T &a_data) 100 | { 101 | assert(m_producerThread.get() != 0); 102 | 103 | m_consumableQueue.Push(a_data); 104 | } 105 | 106 | template 107 | void ConsumerThread::ThreadRoutine() 108 | { 109 | // init function 110 | this->m_initDelegate(); 111 | 112 | // loop to check if the thread must be terminated 113 | while (this->m_terminate.load() == false) 114 | { 115 | T thisElem; 116 | if (this->m_consumableQueue.TimedWaitPop( 117 | thisElem, std::chrono::microseconds(CONSUMER_THREAD_TIMEOUT_USEC))) 118 | { 119 | this->m_consumeDelegate(thisElem); 120 | } 121 | } 122 | } 123 | 124 | #endif /* _CONSUMERTHREADIMPL_H_ */ 125 | -------------------------------------------------------------------------------- /cpp/delegate/Delegate.h: -------------------------------------------------------------------------------- 1 | /// @file Delegate.h 2 | /// @brief This file contains the definition of the Delegate class 3 | /// 4 | /// This file defines the Delegate pattern. 5 | /// http://en.wikipedia.org/wiki/Delegation_pattern 6 | /// the delegation pattern is a technique where an object outwardly expresses 7 | /// certain behaviour but in reality delegates responsibility for implementing 8 | /// that behavior to an associated object in an Inversion of Responsibility 9 | /// 10 | /// It defines delegates from 0 arguments up to 8. Example of use 11 | /// 12 | /// // This defines a delegate that returns void and receives an UInt16 and a std::string 13 | /// Delegate delegateFunction; 14 | /// // This call assigns the delegate to the method f defined in the class A. It will 15 | /// // be called in the context of the object 'obj' 16 | /// delegateFunction = MakeDelegate(&obj, &A::f); 17 | /// // Actual call to the delegate 18 | /// delegateFunction(0, std::string("Hello world")); 19 | 20 | 21 | #ifndef DELEGATE_H_ 22 | #define DELEGATE_H_ 23 | 24 | #include "detail/FastDelegate.h" 25 | 26 | // Define Delegate as a template to be able to use the same name for 27 | // all the different Delegate templates (there is one template per number 28 | // of parameters) 29 | template 30 | class Delegate; 31 | 32 | ///@brief Delegate for functions with 0 arguments 33 | template 34 | class Delegate < RETURN_TYPE ( ) > : 35 | public fastdelegate::FastDelegate < RETURN_TYPE ( ) > 36 | { 37 | public: 38 | typedef fastdelegate::FastDelegate < RETURN_TYPE ( ) > Base_t; 39 | 40 | // default constructor&destructor 41 | Delegate () 42 | {} 43 | ~Delegate() 44 | {} 45 | 46 | // copy constructor 47 | Delegate (const Delegate& source) : 48 | Base_t(source) 49 | {} 50 | 51 | // RETURN_TYPE (X::*xMethod) (void) is the C++ way of describing a pointer to the function xMethod in the class X 52 | template 53 | Delegate (Y *pObject, RETURN_TYPE (X::*XMethod) ()) : 54 | Base_t(pObject, XMethod) 55 | {} 56 | 57 | // The same as above but for const members 58 | template 59 | Delegate (Y *pObject, RETURN_TYPE (X::*XConstMethod) () const) : 60 | Base_t(pObject, XConstMethod) 61 | {} 62 | 63 | // The same as above but for functions that are not part of any class 64 | Delegate (RETURN_TYPE (*function) ()) : 65 | Base_t(function) 66 | {} 67 | 68 | // copying delegates 69 | Delegate& operator= (const Base_t &source) 70 | { 71 | *static_cast(this) = source; 72 | return *this; 73 | } 74 | 75 | // operator to check if the Delegate is valid. It would be the same as !(!Delegate) 76 | // so using !Delegate is faster 77 | operator bool () const 78 | { 79 | return !(static_cast(this)->empty()); 80 | } 81 | }; 82 | 83 | /////////////////////////////////////// 84 | // Global functions to create delegates 85 | 86 | // create a delegate to a non-const function 87 | template 88 | Delegate MakeDelegate ( Y * pObject, RETURN_TYPE (X::*XMethod)() ) 89 | { 90 | return Delegate (pObject, XMethod); // return Delegate on the stack 91 | } 92 | 93 | // create a delegate to a const function 94 | template 95 | Delegate MakeDelegate ( const Y * pObject, RETURN_TYPE (X::*XConstMethod)() const ) 96 | { 97 | return Delegate (pObject, XConstMethod); // return Delegate on the stack 98 | } 99 | 100 | // create a delegate to a static function (without object) 101 | template 102 | Delegate MakeDelegate ( RETURN_TYPE (*Function)() ) 103 | { 104 | return Delegate (Function); // return Delegate on the stack 105 | } 106 | 107 | // N_DELEGATE_ARGS is used as sort of a parameter to include the file detail/DelegateN.h 108 | // depending on that value DelegateN.h will define a Delegate with 1, 2, etc. parameters 109 | // The maximum is 8 since it is the maximum number of parameters defined in FastDelegate.h 110 | #undef N_DELEGATE_ARGS 111 | #define N_DELEGATE_ARGS 1 112 | #include "detail/DelegateN.h" 113 | 114 | #undef N_DELEGATE_ARGS 115 | #define N_DELEGATE_ARGS 2 116 | #include "detail/DelegateN.h" 117 | 118 | #undef N_DELEGATE_ARGS 119 | #define N_DELEGATE_ARGS 3 120 | #include "detail/DelegateN.h" 121 | 122 | #undef N_DELEGATE_ARGS 123 | #define N_DELEGATE_ARGS 4 124 | #include "detail/DelegateN.h" 125 | 126 | #undef N_DELEGATE_ARGS 127 | #define N_DELEGATE_ARGS 5 128 | #include "detail/DelegateN.h" 129 | 130 | #undef N_DELEGATE_ARGS 131 | #define N_DELEGATE_ARGS 6 132 | #include "detail/DelegateN.h" 133 | 134 | #undef N_DELEGATE_ARGS 135 | #define N_DELEGATE_ARGS 7 136 | #include "detail/DelegateN.h" 137 | 138 | #undef N_DELEGATE_ARGS 139 | #define N_DELEGATE_ARGS 8 140 | #include "detail/DelegateN.h" 141 | 142 | #endif /* DELEGATE_H_ */ 143 | -------------------------------------------------------------------------------- /cpp/delegate/detail/DelegateN.h: -------------------------------------------------------------------------------- 1 | /// This file defines a particular delegate depending on the value of 2 | /// N_DELEGATE_ARGS. If it is 1 it will define a delegate with 1 parameter, 3 | /// if it is 2 a delegate with 2 parameters and so on. 4 | /// It also defines MakeDelegate global functions to be used when using the delegate 5 | /// pattern 6 | 7 | #if !defined (N_DELEGATE_ARGS) 8 | #error number of arguments needed to compile the DelegateN.h file 9 | #elif N_DELEGATE_ARGS==1 10 | #define DELEGATE_TEMPLATE_ARGS class Arg1 11 | #define DELEGATE_FUNCTION_ARGS Arg1 p1 12 | #elif N_DELEGATE_ARGS==2 13 | #define DELEGATE_TEMPLATE_ARGS class Arg1, class Arg2 14 | #define DELEGATE_FUNCTION_ARGS Arg1 p1, Arg2 p2 15 | #elif N_DELEGATE_ARGS==3 16 | #define DELEGATE_TEMPLATE_ARGS class Arg1, class Arg2, class Arg3 17 | #define DELEGATE_FUNCTION_ARGS Arg1 p1, Arg2 p2, Arg3 p3 18 | #elif N_DELEGATE_ARGS==4 19 | #define DELEGATE_TEMPLATE_ARGS class Arg1, class Arg2, class Arg3, class Arg4 20 | #define DELEGATE_FUNCTION_ARGS Arg1 p1, Arg2 p2, Arg3 p3, Arg4 p4 21 | #elif N_DELEGATE_ARGS==5 22 | #define DELEGATE_TEMPLATE_ARGS class Arg1, class Arg2, class Arg3, class Arg4, class Arg5 23 | #define DELEGATE_FUNCTION_ARGS Arg1 p1, Arg2 p2, Arg3 p3, Arg4 p4, Arg5 p5 24 | #elif N_DELEGATE_ARGS==6 25 | #define DELEGATE_TEMPLATE_ARGS class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6 26 | #define DELEGATE_FUNCTION_ARGS Arg1 p1, Arg2 p2, Arg3 p3, Arg4 p4, Arg5 p5, Arg6 p6 27 | #elif N_DELEGATE_ARGS==7 28 | #define DELEGATE_TEMPLATE_ARGS class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7 29 | #define DELEGATE_FUNCTION_ARGS Arg1 p1, Arg2 p2, Arg3 p3, Arg4 p4, Arg5 p5, Arg6 p6, Arg7 p7 30 | #elif N_DELEGATE_ARGS==8 31 | #define DELEGATE_TEMPLATE_ARGS class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8 32 | #define DELEGATE_FUNCTION_ARGS Arg1 p1, Arg2 p2, Arg3 p3, Arg4 p4, Arg5 p5, Arg6 p6, Arg7 p7, Arg8 p8 33 | #else 34 | #error the maximum number of arguments to compile the DelegateN.h file is 8 35 | #endif 36 | 37 | 38 | template 39 | class Delegate < RETURN_TYPE ( DELEGATE_FUNCTION_ARGS ) > : 40 | public fastdelegate::FastDelegate < RETURN_TYPE ( DELEGATE_FUNCTION_ARGS ) > 41 | { 42 | public: 43 | typedef fastdelegate::FastDelegate < RETURN_TYPE ( DELEGATE_FUNCTION_ARGS ) > Base_t; 44 | 45 | // default constructor&destructor 46 | Delegate () 47 | {} 48 | ~Delegate() 49 | {} 50 | 51 | // copy constructor 52 | Delegate (const Delegate& source) : 53 | Base_t(source) 54 | {} 55 | 56 | // RETURN_TYPE (X::*xMethod) (void) is the C++ way of describing a pointer to the function xMethod in the class X 57 | template 58 | Delegate (Y *pObject, RETURN_TYPE (X::*xMethod) (DELEGATE_FUNCTION_ARGS)) : 59 | Base_t(pObject, xMethod) 60 | {} 61 | 62 | // The same as above but for const members 63 | template 64 | Delegate (Y *pObject, RETURN_TYPE (X::*xMethod) (DELEGATE_FUNCTION_ARGS) const) : 65 | Base_t(pObject, xMethod) 66 | {} 67 | 68 | // The same as above but for functions that are not part of any class 69 | Delegate (RETURN_TYPE (*function) (DELEGATE_FUNCTION_ARGS)) : 70 | Base_t(function) 71 | {} 72 | 73 | // copying delegates 74 | Delegate& operator= (const Base_t &source) 75 | { 76 | *static_cast(this) = source; 77 | return *this; 78 | } 79 | 80 | // operator to check if the Delegate is valid. It would be the same as !(!Delegate) 81 | // so using !Delegate is faster 82 | operator bool () const 83 | { 84 | // it uses twice the operator ! inside the 85 | return !(static_cast(this)->empty()); 86 | } 87 | }; 88 | 89 | /////////////////////////////////////// 90 | // Global functions to create delegates 91 | 92 | // create a delegate to a non-const function 93 | template 94 | Delegate MakeDelegate ( Y * pObject, RETURN_TYPE (X::*XMethod)(DELEGATE_FUNCTION_ARGS) ) 95 | { 96 | return Delegate (pObject, XMethod); // return Delegate on the stack 97 | } 98 | 99 | // create a delegate to a const function 100 | template 101 | Delegate MakeDelegate ( const Y * pObject, RETURN_TYPE (X::*XConstMethod)(DELEGATE_FUNCTION_ARGS) const ) 102 | { 103 | return Delegate (pObject, XConstMethod); // return Delegate on the stack 104 | } 105 | 106 | // create a delegate to a static function (without object) 107 | template 108 | Delegate MakeDelegate ( RETURN_TYPE (*Function)(DELEGATE_FUNCTION_ARGS) ) 109 | { 110 | return Delegate (Function); // return Delegate on the stack 111 | } 112 | 113 | 114 | #undef DELEGATE_TEMPLATE_ARGS 115 | #undef DELEGATE_FUNCTION_ARGS 116 | -------------------------------------------------------------------------------- /cpp/dummylogger.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2017 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file dummylogger.h 23 | /// @brief A simple log based on C++ streams 24 | /// 25 | /// @author Faustino Frechilla 26 | /// @history 27 | /// Ref Who When What 28 | /// Faustino Frechilla 01-Apr-2017 Original development 29 | /// @endhistory 30 | /// 31 | // ============================================================================ 32 | 33 | #pragma once 34 | 35 | #include 36 | #include "singleton.h" 37 | 38 | 39 | /// @brief 40 | /// This is a singleton class to log messages using C++ streams 41 | /// 42 | /// Example of usage: 43 | /// DummyLogger::instance() << "This is a log message" << std::endl; 44 | class DummyLogger : public Singleton 45 | { 46 | public: 47 | /// @brief getStream returns a reference to the stream being used by this 48 | /// logger instance 49 | /// @return 50 | inline std::ostream& getStream() const 51 | { 52 | return _stream; 53 | } 54 | 55 | /// @brief operator<< operator used to forward log messages into the output stream 56 | /// @param pf 57 | /// @return 58 | DummyLogger& operator<<(std::ostream& (*pf)(std::ostream&)) 59 | { 60 | pf(_stream); 61 | return *this; 62 | } 63 | 64 | private: 65 | /// @brief the strem where log messages will be forwarded 66 | std::ostream& _stream; 67 | 68 | DummyLogger(): _stream(std::cout) 69 | {} 70 | ~DummyLogger() 71 | {} 72 | 73 | // usage of "friend" is discouraged, but it is the only way to design a templatized singleton 74 | friend class Singleton; 75 | 76 | // template method needed to be able to log strings ending with std::endl 77 | template 78 | friend DummyLogger& operator<<(DummyLogger& log, T const& val); 79 | 80 | private: 81 | // prevent copying of this singleton 82 | DummyLogger(const DummyLogger& src); 83 | DummyLogger& operator =(const DummyLogger& src); 84 | 85 | }; // class DummyLogger 86 | 87 | template 88 | DummyLogger& operator<<(DummyLogger& log, T const& val) 89 | { 90 | log._stream << val; 91 | return log; 92 | } 93 | -------------------------------------------------------------------------------- /cpp/lock_free_atomic_ops.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2010 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file lock_free_atomic_ops.h 23 | /// @brief This file contains functions to wrap the built-in atomic operations 24 | /// defined for your compiler 25 | /// 26 | /// @author Faustino Frechilla 27 | /// @history 28 | /// Ref Who When What 29 | /// Faustino Frechilla 11-Jul-2010 Original development. GCC support 30 | /// Faustino Frechilla 08-Aug-2014 Change to MIT license 31 | /// @endhistory 32 | /// 33 | // ============================================================================ 34 | 35 | #ifndef __ATOMIC_OPS_H 36 | #define __ATOMIC_OPS_H 37 | 38 | #ifdef __GNUC__ 39 | // Atomic functions in GCC are present from version 4.1.0 on 40 | // http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 41 | 42 | // Test for GCC >= 4.1.0 43 | #if (__GNUC__ < 4) || \ 44 | ((__GNUC__ == 4) && ((__GNUC_MINOR__ < 1) || \ 45 | ((__GNUC_MINOR__ == 1) && \ 46 | (__GNUC_PATCHLEVEL__ < 0))) ) 47 | 48 | #error Atomic built-in functions are only available in GCC in versions >= 4.1.0 49 | 50 | #endif // end of check for GCC 4.1.0 51 | 52 | /// @brief atomically adds a_count to the variable pointed by a_ptr 53 | /// @return the value that had previously been in memory 54 | #define AtomicAdd(a_ptr,a_count) __sync_fetch_and_add (a_ptr, a_count) 55 | 56 | /// @brief atomically substracts a_count from the variable pointed by a_ptr 57 | /// @return the value that had previously been in memory 58 | #define AtomicSub(a_ptr,a_count) __sync_fetch_and_sub (a_ptr, a_count) 59 | 60 | /// @brief Compare And Swap 61 | /// If the current value of *a_ptr is a_oldVal, then write a_newVal into *a_ptr 62 | /// @return true if the comparison is successful and a_newVal was written 63 | #define CAS(a_ptr, a_oldVal, a_newVal) __sync_bool_compare_and_swap(a_ptr, a_oldVal, a_newVal) 64 | 65 | /// @brief Compare And Swap 66 | /// If the current value of *a_ptr is a_oldVal, then write a_newVal into *a_ptr 67 | /// @return the contents of *a_ptr before the operation 68 | #define CASVal(a_ptr, a_oldVal, a_newVal) __sync_val_compare_and_swap(a_ptr, a_oldVal, a_newVal) 69 | 70 | #else 71 | #error Atomic functions such as CAS or AtomicAdd are not defined for your compiler. Please add them in atomic_ops.h 72 | #endif // __GNUC__ 73 | 74 | #endif // __ATOMIC_OPS_H 75 | -------------------------------------------------------------------------------- /cpp/lock_free_queue.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2010 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file lock_free_queue.h 23 | /// @brief Definition of a circular array based lock-free queue 24 | /// See http://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular 25 | /// for more info 26 | /// 27 | /// @author Faustino Frechilla 28 | /// @history 29 | /// Ref Who When What 30 | /// Faustino Frechilla 11-Jul-2010 Original development 31 | /// Faustino Frechilla 08-Aug-2014 Support for single producer through LOCK_FREE_Q_SINGLE_PRODUCER #define 32 | /// Faustino Frechilla 11-Aug-2014 LOCK_FREE_Q_SINGLE_PRODUCER removed. Single producer handled in template 33 | /// Faustino Frechilla 12-Aug-2014 inheritance (specialisation) based on templates. 34 | /// Faustino Frechilla 10-Aug-2015 Ported to c++11. Removed volatile keywords (using std::atomic) 35 | /// @endhistory 36 | /// 37 | // ============================================================================ 38 | 39 | #ifndef _LOCK_FREE_QUEUE_H__ 40 | #define _LOCK_FREE_QUEUE_H__ 41 | 42 | #include // uint32_t 43 | #include 44 | 45 | // default Queue size 46 | #define LOCK_FREE_Q_DEFAULT_SIZE 65536 // (2^16) 47 | 48 | // define this macro if calls to "size" must return the real size of the 49 | // queue. If it is undefined that function will try to take a snapshot of 50 | // the queue, but returned value might be bogus 51 | //#define _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 52 | 53 | // forward declarations for default template values 54 | // 55 | template 56 | class ArrayLockFreeQueueSingleProducer; 57 | template 58 | class ArrayLockFreeQueueMultipleProducers; 59 | 60 | 61 | /// @brief Lock-free queue based on a circular array 62 | /// No allocation of extra memory for the nodes handling is needed, but it has 63 | /// to add extra overhead (extra CAS operation) when inserting to ensure the 64 | /// thread-safety of the queue when the queue type is not 65 | /// ArrayLockFreeQueueSingleProducer. 66 | /// 67 | /// examples of instantiation: 68 | /// ArrayLockFreeQueue q; // queue of ints of default size (65535 - 1) 69 | /// // and defaulted to single producer 70 | /// ArrayLockFreeQueue q; 71 | /// // queue of ints of size (10000 - 1) and 72 | /// // defaulted to single producer 73 | /// ArrayLockFreeQueue q; 74 | /// // queue of ints of size (100 - 1) with support 75 | /// // for multiple producers 76 | /// 77 | /// ELEM_T represents the type of elementes pushed and popped from the queue 78 | /// Q_SIZE size of the queue. The actual size of the queue is (Q_SIZE-1) 79 | /// This number should be a power of 2 to ensure 80 | /// indexes in the circular queue keep stable when the uint32_t 81 | /// variable that holds the current position rolls over from FFFFFFFF 82 | /// to 0. For instance 83 | /// 2 -> 0x02 84 | /// 4 -> 0x04 85 | /// 8 -> 0x08 86 | /// 16 -> 0x10 87 | /// (...) 88 | /// 1024 -> 0x400 89 | /// 2048 -> 0x800 90 | /// 91 | /// if queue size is not defined as requested, let's say, for 92 | /// instance 100, when current position is FFFFFFFF (4,294,967,295) 93 | /// index in the circular array is 4,294,967,295 % 100 = 95. 94 | /// When that value is incremented it will be set to 0, that is the 95 | /// last 4 elements of the queue are not used when the counter rolls 96 | /// over to 0 97 | /// Q_TYPE type of queue implementation. ArrayLockFreeQueueSingleProducer and 98 | /// ArrayLockFreeQueueMultipleProducers are supported (single producer 99 | /// by default) 100 | template < 101 | typename ELEM_T, 102 | uint32_t Q_SIZE = LOCK_FREE_Q_DEFAULT_SIZE, 103 | template class Q_TYPE = ArrayLockFreeQueueSingleProducer > 104 | class ArrayLockFreeQueue 105 | { 106 | public: 107 | /// @brief constructor of the class 108 | ArrayLockFreeQueue(); 109 | 110 | /// @brief destructor of the class. 111 | /// Note it is not virtual since it is not expected to inherit from this 112 | /// template 113 | ~ArrayLockFreeQueue(); 114 | 115 | /// @brief returns the current number of items in the queue 116 | /// It tries to take a snapshot of the size of the queue, but in busy environments 117 | /// this function might return bogus values. 118 | /// 119 | /// If a reliable queue size must be kept you might want to have a look at 120 | /// the preprocessor variable in this header file called '_WITH_LOCK_FREE_Q_KEEP_REAL_SIZE' 121 | /// it enables a reliable size though it hits overall performance of the queue 122 | /// (when the reliable size variable is on it's got an impact of about 20% in time) 123 | inline uint32_t size(); 124 | 125 | /// @brief return true if the queue is full. False otherwise 126 | /// It tries to take a snapshot of the size of the queue, but in busy 127 | /// environments this function might return bogus values. See help in method 128 | /// ArrayLockFreeQueue::size 129 | inline bool full(); 130 | 131 | /// @brief push an element at the tail of the queue 132 | /// @param the element to insert in the queue 133 | /// Note that the element is not a pointer or a reference, so if you are using large data 134 | /// structures to be inserted in the queue you should think of instantiate the template 135 | /// of the queue as a pointer to that large structure 136 | /// @return true if the element was inserted in the queue. False if the queue was full 137 | inline bool push(const ELEM_T &a_data); 138 | 139 | /// @brief pop the element at the head of the queue 140 | /// @param a reference where the element in the head of the queue will be saved to 141 | /// Note that the a_data parameter might contain rubbish if the function returns false 142 | /// @return true if the element was successfully extracted from the queue. False if the queue was empty 143 | inline bool pop(ELEM_T &a_data); 144 | 145 | protected: 146 | /// @brief the actual queue. methods are forwarded into the real 147 | /// implementation 148 | Q_TYPE m_qImpl; 149 | 150 | private: 151 | /// @brief disable copy constructor declaring it private 152 | ArrayLockFreeQueue( 153 | const ArrayLockFreeQueue &a_src); 154 | }; 155 | 156 | /// @brief implementation of an array based lock free queue with support for a 157 | /// single producer 158 | /// This class is prevented from being instantiated directly (all members and 159 | /// methods are private). To instantiate a single producer lock free queue 160 | /// you must use the ArrayLockFreeQueue fachade: 161 | /// ArrayLockFreeQueue q; 162 | template 163 | class ArrayLockFreeQueueSingleProducer 164 | { 165 | // ArrayLockFreeQueue will be using this' private members 166 | template < 167 | typename ELEM_T_, 168 | uint32_t Q_SIZE_, 169 | template class Q_TYPE> 170 | friend class ArrayLockFreeQueue; 171 | 172 | private: 173 | /// @brief constructor of the class 174 | ArrayLockFreeQueueSingleProducer(); 175 | virtual ~ArrayLockFreeQueueSingleProducer(); 176 | 177 | inline uint32_t size(); 178 | 179 | inline bool full(); 180 | 181 | bool push(const ELEM_T &a_data); 182 | 183 | bool pop(ELEM_T &a_data); 184 | 185 | /// @brief calculate the index in the circular array that corresponds 186 | /// to a particular "count" value 187 | inline uint32_t countToIndex(uint32_t a_count); 188 | 189 | private: 190 | /// @brief array to keep the elements 191 | ELEM_T m_theQueue[Q_SIZE]; 192 | 193 | /// @brief where a new element will be inserted 194 | std::atomic m_writeIndex; 195 | 196 | /// @brief where the next element where be extracted from 197 | std::atomic m_readIndex; 198 | 199 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 200 | /// @brief number of elements in the queue 201 | std::atomic m_count; 202 | #endif 203 | 204 | private: 205 | /// @brief disable copy constructor declaring it private 206 | ArrayLockFreeQueueSingleProducer( 207 | const ArrayLockFreeQueueSingleProducer &a_src); 208 | }; 209 | 210 | /// @brief implementation of an array based lock free queue with support for 211 | /// multiple producers 212 | /// This class is prevented from being instantiated directly (all members and 213 | /// methods are private). To instantiate a multiple producers lock free queue 214 | /// you must use the ArrayLockFreeQueue fachade: 215 | /// ArrayLockFreeQueue q; 216 | template 217 | class ArrayLockFreeQueueMultipleProducers 218 | { 219 | // ArrayLockFreeQueue will be using this' private members 220 | template < 221 | typename ELEM_T_, 222 | uint32_t Q_SIZE_, 223 | template class Q_TYPE> 224 | friend class ArrayLockFreeQueue; 225 | 226 | private: 227 | /// @brief constructor of the class 228 | ArrayLockFreeQueueMultipleProducers(); 229 | 230 | virtual ~ArrayLockFreeQueueMultipleProducers(); 231 | 232 | inline uint32_t size(); 233 | 234 | inline bool full(); 235 | 236 | bool push(const ELEM_T &a_data); 237 | 238 | bool pop(ELEM_T &a_data); 239 | 240 | /// @brief calculate the index in the circular array that corresponds 241 | /// to a particular "count" value 242 | inline uint32_t countToIndex(uint32_t a_count); 243 | 244 | private: 245 | /// @brief array to keep the elements 246 | ELEM_T m_theQueue[Q_SIZE]; 247 | 248 | /// @brief where a new element will be inserted 249 | std::atomic m_writeIndex; 250 | 251 | /// @brief where the next element where be extracted from 252 | std::atomic m_readIndex; 253 | 254 | /// @brief maximum read index for multiple producer queues 255 | /// If it's not the same as m_writeIndex it means 256 | /// there are writes pending to be "committed" to the queue, that means, 257 | /// the place for the data was reserved (the index in the array) but 258 | /// data is still not in the queue, so the thread trying to read will have 259 | /// to wait for those other threads to save the data into the queue 260 | /// 261 | /// note this is only used for multiple producers 262 | std::atomic m_maximumReadIndex; 263 | 264 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 265 | /// @brief number of elements in the queue 266 | std::atomic m_count; 267 | #endif 268 | 269 | private: 270 | /// @brief disable copy constructor declaring it private 271 | ArrayLockFreeQueueMultipleProducers( 272 | const ArrayLockFreeQueueMultipleProducers &a_src); 273 | }; 274 | 275 | // include implementation files 276 | #include "lock_free_queue_impl.h" 277 | #include "lock_free_queue_impl_single_producer.h" 278 | #include "lock_free_queue_impl_multiple_producer.h" 279 | 280 | #endif // _LOCK_FREE_QUEUE_H__ 281 | -------------------------------------------------------------------------------- /cpp/lock_free_queue_impl.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2010 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file lock_free_queue_impl.h 23 | /// @brief Implementation of a circular array based lock-free queue 24 | /// See http://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular 25 | /// for more info 26 | /// 27 | /// @author Faustino Frechilla 28 | /// @history 29 | /// Ref Who When What 30 | /// Faustino Frechilla 11-Jul-2010 Original development 31 | /// Faustino Frechilla 08-Aug-2014 Support for single producer through LOCK_FREE_Q_SINGLE_PRODUCER #define 32 | /// Faustino Frechilla 11-Aug-2014 LOCK_FREE_Q_SINGLE_PRODUCER removed. Single/multiple producer handled in templates 33 | /// Faustino Frechilla 12-Aug-2014 inheritance (specialisation) based on templates. 34 | /// @endhistory 35 | /// 36 | // ============================================================================ 37 | 38 | #ifndef __LOCK_FREE_QUEUE_IMPL_H__ 39 | #define __LOCK_FREE_QUEUE_IMPL_H__ 40 | 41 | #include // assert() 42 | 43 | template < 44 | typename ELEM_T, 45 | uint32_t Q_SIZE, 46 | template class Q_TYPE> 47 | ArrayLockFreeQueue::ArrayLockFreeQueue(): 48 | m_qImpl() 49 | { 50 | } 51 | 52 | template < 53 | typename ELEM_T, 54 | uint32_t Q_SIZE, 55 | template class Q_TYPE> 56 | ArrayLockFreeQueue::~ArrayLockFreeQueue() 57 | { 58 | } 59 | 60 | template < 61 | typename ELEM_T, 62 | uint32_t Q_SIZE, 63 | template class Q_TYPE> 64 | inline uint32_t ArrayLockFreeQueue::size() 65 | { 66 | return m_qImpl.size(); 67 | } 68 | 69 | template < 70 | typename ELEM_T, 71 | uint32_t Q_SIZE, 72 | template class Q_TYPE> 73 | inline bool ArrayLockFreeQueue::full() 74 | { 75 | return m_qImpl.full(); 76 | } 77 | 78 | template < 79 | typename ELEM_T, 80 | uint32_t Q_SIZE, 81 | template class Q_TYPE> 82 | inline bool ArrayLockFreeQueue::push(const ELEM_T &a_data) 83 | { 84 | return m_qImpl.push(a_data); 85 | } 86 | 87 | template < 88 | typename ELEM_T, 89 | uint32_t Q_SIZE, 90 | template class Q_TYPE> 91 | inline bool ArrayLockFreeQueue::pop(ELEM_T &a_data) 92 | { 93 | return m_qImpl.pop(a_data); 94 | } 95 | 96 | #endif // __LOCK_FREE_QUEUE_IMPL_H__ 97 | -------------------------------------------------------------------------------- /cpp/lock_free_queue_impl_multiple_producer.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2010 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file lock_free_queue_impl_multiple_producer.h 23 | /// @brief Implementation of a circular array based lock-free queue 24 | /// See http://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular 25 | /// for more info 26 | /// 27 | /// @author Faustino Frechilla 28 | /// @history 29 | /// Ref Who When What 30 | /// Faustino Frechilla 11-Aug-2014 Original development. File containing only specifics for multiple producers 31 | /// Faustino Frechilla 12-Aug-2014 inheritance (specialisation) based on templates 32 | /// Faustino Frechilla 10-Aug-2015 Ported to c++11. Removed volatile keywords (using std::atomic) 33 | /// @endhistory 34 | /// 35 | // ============================================================================ 36 | 37 | #ifndef __LOCK_FREE_QUEUE_IMPL_MULTIPLE_PRODUCER_H__ 38 | #define __LOCK_FREE_QUEUE_IMPL_MULTIPLE_PRODUCER_H__ 39 | 40 | #include // assert() 41 | #include // sched_yield() 42 | 43 | template 44 | ArrayLockFreeQueueMultipleProducers::ArrayLockFreeQueueMultipleProducers(): 45 | m_writeIndex(0), // initialisation is not atomic 46 | m_readIndex(0), // 47 | m_maximumReadIndex(0) // 48 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 49 | ,m_count(0) // 50 | #endif 51 | {} 52 | 53 | template 54 | ArrayLockFreeQueueMultipleProducers::~ArrayLockFreeQueueMultipleProducers() 55 | {} 56 | 57 | template 58 | inline 59 | uint32_t ArrayLockFreeQueueMultipleProducers::countToIndex(uint32_t a_count) 60 | { 61 | // if Q_SIZE is a power of 2 this statement could be also written as 62 | // return (a_count & (Q_SIZE - 1)); 63 | return (a_count % Q_SIZE); 64 | } 65 | 66 | template 67 | inline 68 | uint32_t ArrayLockFreeQueueMultipleProducers::size() 69 | { 70 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 71 | 72 | return m_count.load(); 73 | #else 74 | 75 | uint32_t currentWriteIndex = m_maximumReadIndex.load(); 76 | uint32_t currentReadIndex = m_readIndex.load(); 77 | 78 | // let's think of a scenario where this function returns bogus data 79 | // 1. when the statement 'currentWriteIndex = m_maximumReadIndex' is run 80 | // m_maximumReadIndex is 3 and m_readIndex is 2. Real size is 1 81 | // 2. afterwards this thread is preemted. While this thread is inactive 2 82 | // elements are inserted and removed from the queue, so m_maximumReadIndex 83 | // is 5 and m_readIndex 4. Real size is still 1 84 | // 3. Now the current thread comes back from preemption and reads m_readIndex. 85 | // currentReadIndex is 4 86 | // 4. currentReadIndex is bigger than currentWriteIndex, so 87 | // m_totalSize + currentWriteIndex - currentReadIndex is returned, that is, 88 | // it returns that the queue is almost full, when it is almost empty 89 | // 90 | if (countToIndex(currentWriteIndex) >= countToIndex(currentReadIndex)) 91 | { 92 | return (currentWriteIndex - currentReadIndex); 93 | } 94 | else 95 | { 96 | return (Q_SIZE + currentWriteIndex - currentReadIndex); 97 | } 98 | #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 99 | } 100 | 101 | template 102 | inline 103 | bool ArrayLockFreeQueueMultipleProducers::full() 104 | { 105 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 106 | 107 | return (m_count.load() == (Q_SIZE - 1)); 108 | #else 109 | 110 | uint32_t currentWriteIndex = m_writeIndex; 111 | uint32_t currentReadIndex = m_readIndex; 112 | 113 | if (countToIndex(currentWriteIndex + 1) == countToIndex(currentReadIndex)) 114 | { 115 | // the queue is full 116 | return true; 117 | } 118 | else 119 | { 120 | // not full! 121 | return false; 122 | } 123 | #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 124 | } 125 | 126 | template 127 | bool ArrayLockFreeQueueMultipleProducers::push(const ELEM_T &a_data) 128 | { 129 | uint32_t currentWriteIndex; 130 | 131 | do 132 | { 133 | currentWriteIndex = m_writeIndex.load(); 134 | 135 | if (countToIndex(currentWriteIndex + 1) == countToIndex(m_readIndex.load())) 136 | { 137 | // the queue is full 138 | return false; 139 | } 140 | // There is more than one producer. Keep looping till this thread is able 141 | // to allocate space for current piece of data 142 | // 143 | // using compare_exchange_strong because it isn't allowed to fail spuriously 144 | // When the compare_exchange operation is in a loop the weak version 145 | // will yield better performance on some platforms, but here we'd have to 146 | // load m_writeIndex all over again 147 | } while (!m_writeIndex.compare_exchange_strong( 148 | currentWriteIndex, (currentWriteIndex + 1))); 149 | 150 | // Just made sure this index is reserved for this thread. 151 | m_theQueue[countToIndex(currentWriteIndex)] = a_data; 152 | 153 | // update the maximum read index after saving the piece of data. It can't 154 | // fail if there is only one thread inserting in the queue. It might fail 155 | // if there is more than 1 producer thread because this operation has to 156 | // be done in the same order as the previous CAS 157 | // 158 | // using compare_exchange_weak because they are allowed to fail spuriously 159 | // (act as if *this != expected, even if they are equal), but when the 160 | // compare_exchange operation is in a loop the weak version will yield 161 | // better performance on some platforms. 162 | while (!m_maximumReadIndex.compare_exchange_weak( 163 | currentWriteIndex, (currentWriteIndex + 1))) 164 | { 165 | // this is a good place to yield the thread in case there are more 166 | // software threads than hardware processors and you have more 167 | // than 1 producer thread 168 | // have a look at sched_yield (POSIX.1b) 169 | //sched_yield(); 170 | } 171 | 172 | // The value was successfully inserted into the queue 173 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 174 | m_count.fetch_add(1); 175 | #endif 176 | 177 | return true; 178 | } 179 | 180 | template 181 | bool ArrayLockFreeQueueMultipleProducers::pop(ELEM_T &a_data) 182 | { 183 | uint32_t currentReadIndex; 184 | 185 | do 186 | { 187 | currentReadIndex = m_readIndex.load(); 188 | 189 | // to ensure thread-safety when there is more than 1 producer 190 | // thread a second index is defined (m_maximumReadIndex) 191 | if (countToIndex(currentReadIndex) == countToIndex(m_maximumReadIndex.load())) 192 | { 193 | // the queue is empty or 194 | // a producer thread has allocate space in the queue but is 195 | // waiting to commit the data into it 196 | return false; 197 | } 198 | 199 | // retrieve the data from the queue 200 | a_data = m_theQueue[countToIndex(currentReadIndex)]; 201 | 202 | // try to perfrom now the CAS operation on the read index. If we succeed 203 | // a_data already contains what m_readIndex pointed to before we 204 | // increased it 205 | if (m_readIndex.compare_exchange_strong(currentReadIndex, (currentReadIndex + 1))) 206 | { 207 | // got here. The value was retrieved from the queue. Note that the 208 | // data inside the m_queue array is not deleted nor reseted 209 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 210 | m_count.fetch_sub(1); 211 | #endif 212 | return true; 213 | } 214 | 215 | // it failed retrieving the element off the queue. Someone else must 216 | // have read the element stored at countToIndex(currentReadIndex) 217 | // before we could perform the CAS operation 218 | 219 | } while(1); // keep looping to try again! 220 | 221 | // Something went wrong. it shouldn't be possible to reach here 222 | assert(0); 223 | 224 | // Add this return statement to avoid compiler warnings 225 | return false; 226 | } 227 | 228 | #endif // __LOCK_FREE_QUEUE_IMPL_MULTIPLE_PRODUCER_H__ 229 | -------------------------------------------------------------------------------- /cpp/lock_free_queue_impl_single_producer.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2010 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file lock_free_queue_impl_single_producer.h 23 | /// @brief Implementation of a circular array based lock-free queue 24 | /// See http://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular 25 | /// for more info 26 | /// 27 | /// @author Faustino Frechilla 28 | /// @history 29 | /// Ref Who When What 30 | /// Faustino Frechilla 11-Aug-2014 Original development. File containing only specifics for single producer 31 | /// Faustino Frechilla 12-Aug-2014 inheritance (specialisation) based on templates 32 | /// Faustino Frechilla 10-Aug-2015 Ported to c++11. Removed volatile keywords (using std::atomic) 33 | /// @endhistory 34 | /// 35 | // ============================================================================ 36 | 37 | #ifndef __LOCK_FREE_QUEUE_IMPL_SINGLE_PRODUCER_H__ 38 | #define __LOCK_FREE_QUEUE_IMPL_SINGLE_PRODUCER_H__ 39 | 40 | #include // assert() 41 | 42 | template 43 | ArrayLockFreeQueueSingleProducer::ArrayLockFreeQueueSingleProducer(): 44 | m_writeIndex(0), // initialisation is not atomic 45 | m_readIndex(0) // 46 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 47 | ,m_count(0) // 48 | #endif 49 | {} 50 | 51 | template 52 | ArrayLockFreeQueueSingleProducer::~ArrayLockFreeQueueSingleProducer() 53 | {} 54 | 55 | template 56 | inline 57 | uint32_t ArrayLockFreeQueueSingleProducer::countToIndex(uint32_t a_count) 58 | { 59 | // if Q_SIZE is a power of 2 this statement could be also written as 60 | // return (a_count & (Q_SIZE - 1)); 61 | return (a_count % Q_SIZE); 62 | } 63 | 64 | template 65 | inline 66 | uint32_t ArrayLockFreeQueueSingleProducer::size() 67 | { 68 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 69 | return m_count.load(); 70 | #else 71 | uint32_t currentWriteIndex = m_writeIndex.load(); 72 | uint32_t currentReadIndex = m_readIndex.load(); 73 | 74 | // let's think of a scenario where this function returns bogus data 75 | // 1. when the statement 'currentWriteIndex = m_writeIndex' is run 76 | // m_writeIndex is 3 and m_readIndex is 2. Real size is 1 77 | // 2. afterwards this thread is preemted. While this thread is inactive 2 78 | // elements are inserted and removed from the queue, so m_writeIndex is 5 79 | // m_readIndex 4. Real size is still 1 80 | // 3. Now the current thread comes back from preemption and reads m_readIndex. 81 | // currentReadIndex is 4 82 | // 4. currentReadIndex is bigger than currentWriteIndex, so 83 | // m_totalSize + currentWriteIndex - currentReadIndex is returned, that is, 84 | // it returns that the queue is almost full, when it is almost empty 85 | // 86 | if (countToIndex(currentWriteIndex) >= countToIndex(currentReadIndex)) 87 | { 88 | return (currentWriteIndex - currentReadIndex); 89 | } 90 | else 91 | { 92 | return (Q_SIZE + currentWriteIndex - currentReadIndex); 93 | } 94 | #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 95 | } 96 | 97 | template 98 | inline 99 | bool ArrayLockFreeQueueSingleProducer::full() 100 | { 101 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 102 | return (m_count.load() == (Q_SIZE - 1)); 103 | #else 104 | uint32_t currentWriteIndex = m_writeIndex.load(); 105 | uint32_t currentReadIndex = m_readIndex.load(); 106 | 107 | if (countToIndex(currentWriteIndex + 1) == countToIndex(currentReadIndex)) 108 | { 109 | // the queue is full 110 | return true; 111 | } 112 | else 113 | { 114 | // not full! 115 | return false; 116 | } 117 | #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 118 | } 119 | 120 | template 121 | bool ArrayLockFreeQueueSingleProducer::push(const ELEM_T &a_data) 122 | { 123 | uint32_t currentWriteIndex; 124 | 125 | // no need to loop. There is only one producer (this thread) 126 | currentWriteIndex = m_writeIndex.load(); 127 | 128 | if (countToIndex(currentWriteIndex + 1) == 129 | countToIndex(m_readIndex.load())) 130 | { 131 | // the queue is full 132 | return false; 133 | } 134 | 135 | // up to this point we made sure there is space in the Q for more data 136 | m_theQueue[countToIndex(currentWriteIndex)] = a_data; 137 | 138 | // increment write index 139 | m_writeIndex.fetch_add(1); 140 | 141 | // The value was successfully inserted into the queue 142 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 143 | m_count.fetch_add(1); 144 | #endif 145 | 146 | return true; 147 | } 148 | 149 | template 150 | bool ArrayLockFreeQueueSingleProducer::pop(ELEM_T &a_data) 151 | { 152 | uint32_t currentReadIndex; 153 | 154 | do 155 | { 156 | currentReadIndex = m_readIndex.load(); 157 | 158 | if (countToIndex(currentReadIndex) == 159 | countToIndex(m_writeIndex.load())) 160 | { 161 | // queue is empty 162 | return false; 163 | } 164 | 165 | // retrieve the data from the queue 166 | a_data = m_theQueue[countToIndex(currentReadIndex)]; 167 | 168 | // try to perfrom now the CAS operation on the read index. If we succeed 169 | // a_data already contains what m_readIndex pointed to before we 170 | // increased it. 171 | // using compare_exchange_strong because it isn't allowed to fail spuriously 172 | // (act as if *this != expected, even if they are equal) 173 | // When the compare_exchange operation is in a loop the weak version 174 | // will yield better performance on some platforms (but here we'd have to 175 | // load m_writeIndex all over again, better not to fail spuriously) 176 | if (m_readIndex.compare_exchange_strong( 177 | currentReadIndex, (currentReadIndex + 1))) 178 | { 179 | // got here. The value was retrieved from the queue. Note that the 180 | // data inside the m_queue array is not deleted nor reseted 181 | #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE 182 | m_count.fetch_sub(1); 183 | #endif 184 | return true; 185 | } 186 | 187 | // it failed retrieving the element off the queue. Someone else must 188 | // have read the element stored at countToIndex(currentReadIndex) 189 | // before we could perform the CAS operation 190 | 191 | } while(1); // keep looping to try again! 192 | 193 | // Something went wrong. it shouldn't be possible to reach here 194 | assert(0); 195 | 196 | // Add this return statement to avoid compiler warnings 197 | return false; 198 | } 199 | 200 | #endif // __LOCK_FREE_QUEUE_IMPL_SINGLE_PRODUCER_H__ 201 | 202 | -------------------------------------------------------------------------------- /cpp/safe_queue.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2009-2013 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file safe_queue.h 23 | /// @brief Definition of a thread-safe queue based on c++11 std calls 24 | /// It internally contains a std::queue which is protected from concurrent 25 | /// access by std mutexes and conditional variables 26 | /// 27 | /// Your compiler must have support for c++11. This is an example of how to 28 | /// compile an application that makes use of this queue with gcc 4.8: 29 | /// $ g++ -g -O0 -Wall -std=c++11 -D_REENTRANT -c app.cpp 30 | /// $ g++ app.o -o app 31 | /// 32 | /// @author Faustino Frechilla 33 | /// @history 34 | /// Ref Who When What 35 | /// Faustino Frechilla 04-May-2009 Original development (based on pthreads) 36 | /// Faustino Frechilla 19-May-2010 Ported to glib. Removed pthread dependency 37 | /// Faustino Frechilla 06-Jun-2013 Ported to c++11. Removed glib dependency 38 | /// Faustino Frechilla 19-Mar-2014 Copy/move constructor, operator= and move assignment 39 | /// @endhistory 40 | /// 41 | // ============================================================================ 42 | 43 | #ifndef _SAFEQUEUE_H_ 44 | #define _SAFEQUEUE_H_ 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include // std::numeric_limits<>::max 51 | 52 | #define SAFE_QUEUE_DEFAULT_MAX_SIZE std::numeric_limits::max() 53 | 54 | /// @brief thread-safe queue 55 | /// It uses a mutex+condition variables to protect the internal queue 56 | /// implementation. Inserting or reading elements use the same mutex 57 | template 58 | class SafeQueue 59 | { 60 | public: 61 | /// @brief constructor 62 | /// @param a_maxSize optional parameter with the maximum size of the queue 63 | SafeQueue(std::size_t a_maxSize = SAFE_QUEUE_DEFAULT_MAX_SIZE); 64 | 65 | /// @brief destructor 66 | ~SafeQueue(); 67 | 68 | /// @brief copy contructor 69 | /// WARNING: Use with great care, this function call can take a long time 70 | /// and block other threads from pushing/popping elements into the source 71 | /// queue 72 | SafeQueue(const SafeQueue& a_src); 73 | 74 | /// @brief operator= overloading 75 | /// This function blocks the a_src and "this" SafeQueues and copies the 76 | /// contents of a_src into "this" SafeQueue. 77 | /// WARNING: Use with great care, this function call can take a long time 78 | /// and block other threads from pushing/popping elements into the queues 79 | /// @param a_src the "right" side of the operator= 80 | /// @return a const reference to this object 81 | const SafeQueue& operator=(const SafeQueue &a_src); 82 | 83 | /// @brief move contructor 84 | SafeQueue(SafeQueue&& a_src); 85 | 86 | /// @brief move assignment 87 | SafeQueue& operator=(SafeQueue&& a_src); 88 | 89 | /// @brief Check if the queue is empty 90 | /// This call can block if another thread owns the lock that protects the 91 | /// queue 92 | /// @return true if the queue is empty. False otherwise 93 | bool IsEmpty() const; 94 | 95 | /// @brief inserts an element into queue queue 96 | /// This call can block if another thread owns the lock that protects the 97 | /// queue. If the queue is full The thread will be blocked in this queue 98 | /// until someone else gets an element from the queue 99 | /// @param element to insert into the queue 100 | void Push(const T &a_elem); 101 | 102 | /// @brief inserts an element into queue queue 103 | /// This call can block if another thread owns the lock that protects the 104 | /// queue. If the queue is full The call will return false and the element 105 | /// won't be inserted 106 | /// @param element to insert into the queue 107 | /// @return True if the elem was successfully inserted into the queue. 108 | /// False otherwise 109 | bool TryPush(const T &a_elem); 110 | 111 | /// @brief extracts an element from the queue (and deletes it from the q) 112 | /// If the queue is empty this call will block the thread until there is 113 | /// something in the queue to be extracted 114 | /// @param a reference where the element from the queue will be saved to 115 | void Pop(T &out_data); 116 | 117 | /// @brief extracts an element from the queue (and deletes it from the q) 118 | /// This call gets the block that protects the queue. It will extract the 119 | /// element from the queue only if there are elements in it 120 | /// @param reference to the variable where the result will be saved 121 | /// @return True if the element was retrieved from the queue. 122 | /// False if the queue was empty 123 | bool TryPop(T &out_data); 124 | 125 | /// @brief extracts an element from the queue (and deletes it from the q) 126 | /// If the queue is empty this call will block the thread until there 127 | /// is something in the queue to be extracted or until the timer 128 | /// (2nd parameter) expires 129 | /// @param reference to the variable where the result will be saved 130 | /// @param duration to wait before returning if the queue was empty 131 | /// you may also pass into this a std::seconds or std::milliseconds 132 | /// (defined in std::chrono) 133 | /// @return True if the element was retrieved from the queue. 134 | /// False if the timeout was hit and nothing could be extracted 135 | /// from the queue 136 | bool TimedWaitPop(T &data, std::chrono::microseconds a_microsecs); 137 | 138 | protected: 139 | /// the actual queue data structure protected by this SafeQueue wrapper 140 | std::queue m_theQueue; 141 | /// maximum number of elements for the queue 142 | std::size_t m_maximumSize; 143 | /// Mutex to protect the queue 144 | mutable std::mutex m_mutex; 145 | /// Conditional variable to wake up threads 146 | mutable std::condition_variable m_cond; 147 | 148 | /// @brief calculate if copying a_src into this instance will need to 149 | /// wake up potential threads waiting to perform push or pop ops. 150 | /// WARNING: It assumes the caller holds all mutexes required to access 151 | /// to the data of this and a_src SafeQueues 152 | /// @param a_src const reference to the SafeQueue that will be copied 153 | /// into this object 154 | /// @return true if threads will need to be waken up. False otherwise 155 | inline bool WakeUpSignalNeeded(const SafeQueue &a_src) const; 156 | }; 157 | 158 | // include the implementation file 159 | #include "safe_queue_impl.h" 160 | 161 | #endif /* _SAFEQUEUE_H_ */ 162 | 163 | -------------------------------------------------------------------------------- /cpp/safe_queue_impl.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2009-2013 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file safe_queue_impl.h 23 | /// @brief Implementation of a thread-safe queue based on c++11 std calls 24 | /// It internally contains a std::queue which is protected from concurrent 25 | /// access by std mutexes and conditional variables 26 | /// 27 | /// @author Faustino Frechilla 28 | /// @history 29 | /// Ref Who When What 30 | /// Faustino Frechilla 04-May-2009 Original development (based on pthreads) 31 | /// Faustino Frechilla 19-May-2010 Ported to glib. Removed pthread dependency 32 | /// Faustino Frechilla 06-Jun-2013 Ported to c++11. Removed glib dependency 33 | /// Faustino Frechilla 13-Dec-2013 Handling spurious wakeups in TimedWaitPop 34 | /// Faustino Frechilla 19-Mar-2014 Copy/move constructor, operator= and move assignment 35 | /// @endhistory 36 | /// 37 | // ============================================================================ 38 | 39 | #ifndef _SAFEQUEUEIMPL_H_ 40 | #define _SAFEQUEUEIMPL_H_ 41 | 42 | template 43 | SafeQueue::SafeQueue(std::size_t a_maxSize): 44 | m_theQueue(), 45 | m_maximumSize(a_maxSize), 46 | m_mutex(), 47 | m_cond() 48 | { 49 | } 50 | 51 | template 52 | SafeQueue::~SafeQueue() 53 | { 54 | } 55 | 56 | template 57 | SafeQueue::SafeQueue(const SafeQueue& a_src): 58 | m_theQueue(), 59 | m_maximumSize(0), 60 | m_mutex(), 61 | m_cond() 62 | { 63 | // copying a safe queue involves only copying the data (m_theQueue and 64 | // m_maximumSize). This object has not been instantiated yet so nobody can 65 | // be trying to perform push or pop operations on it, but we need to 66 | // acquire a_src.m_mutex before copying its data into m_theQueue and 67 | // m_maximumSize 68 | std::unique_lock lk(a_src.m_mutex); 69 | 70 | this->m_maximumSize = a_src.m_maximumSize; 71 | this->m_theQueue = a_src.m_theQueue; 72 | } 73 | 74 | template 75 | const SafeQueue& SafeQueue::operator=(const SafeQueue &a_src) 76 | { 77 | if (this != &a_src) 78 | { 79 | // lock both mutexes at the same time to avoid deadlocks 80 | std::unique_lock this_lk(this->m_mutex, std::defer_lock); 81 | std::unique_lock src_lk (a_src.m_mutex, std::defer_lock); 82 | std::lock(this_lk, src_lk); 83 | 84 | // will we need to wake up waiting threads after copying the source 85 | // queue? 86 | bool wakeUpWaitingThreads = WakeUpSignalNeeded(a_src); 87 | 88 | // copy data from the left side of the operator= into this intance 89 | this->m_maximumSize = a_src.m_maximumSize; 90 | this->m_theQueue = a_src.m_theQueue; 91 | 92 | // time now to wake up threads waiting for data to be inserted 93 | // or extracted 94 | if (wakeUpWaitingThreads) 95 | { 96 | this->m_cond.notify_all(); 97 | } 98 | } 99 | 100 | return *this; 101 | } 102 | 103 | template 104 | SafeQueue::SafeQueue(SafeQueue&& a_src): 105 | m_theQueue(a_src.m_theQueue), // implicit std::move(a_src.m_theQueue) 106 | m_maximumSize(a_src.m_maximumSize), // move constructor called implicitly 107 | m_mutex(), // instantiate a new mutex 108 | m_cond() // instantiate a new conditional variable 109 | { 110 | // This object has not been instantiated yet. We can assume no one is using 111 | // its mutex. 112 | // Also, a_src is a temporary object so there is no need to acquire 113 | // its mutex. 114 | // Things can therefore be safely moved without the need for any mutex or 115 | // conditional variable 116 | } 117 | 118 | template 119 | SafeQueue& SafeQueue::operator=(SafeQueue &&a_src) 120 | { 121 | if (this != &a_src) 122 | { 123 | // make sure we hold this mutex before moving things around. a_src is 124 | // a temporary object so no need to hold its mutex 125 | std::unique_lock lk(this->m_mutex); 126 | 127 | // will we need to wake up waiting threads after copying the source 128 | // queue? 129 | bool wakeUpWaitingThreads = WakeUpSignalNeeded(a_src); 130 | 131 | // process data from the temporary copy into this intance 132 | this->m_maximumSize = std::move(a_src.m_maximumSize); 133 | this->m_theQueue = std::move(a_src.m_theQueue); 134 | 135 | // time now to wake up threads waiting for data to be inserted 136 | // or extracted 137 | if (wakeUpWaitingThreads) 138 | { 139 | this->m_cond.notify_all(); 140 | } 141 | } 142 | 143 | return *this; 144 | } 145 | 146 | template 147 | bool SafeQueue::WakeUpSignalNeeded(const SafeQueue &a_src) const 148 | { 149 | if (this->m_theQueue.empty() && (!a_src.m_theQueue.empty())) 150 | { 151 | // threads waiting for stuff to be popped off the queue 152 | return true; 153 | } 154 | else if ((this->m_theQueue.size() >= this->m_maximumSize) && 155 | (a_src.m_theQueue.size() < a_src.m_maximumSize)) 156 | { 157 | // threads waiting for stuff to be pushed into the queue 158 | return true; 159 | } 160 | 161 | return false; 162 | } 163 | 164 | template 165 | bool SafeQueue::IsEmpty() const 166 | { 167 | std::lock_guard lk(m_mutex); 168 | return m_theQueue.empty(); 169 | } 170 | 171 | template 172 | void SafeQueue::Push(const T &a_elem) 173 | { 174 | std::unique_lock lk(m_mutex); 175 | 176 | while (m_theQueue.size() >= m_maximumSize) 177 | { 178 | m_cond.wait(lk); 179 | } 180 | 181 | bool queueEmpty = m_theQueue.empty(); 182 | 183 | m_theQueue.push(a_elem); 184 | 185 | if (queueEmpty) 186 | { 187 | // wake up threads waiting for stuff 188 | m_cond.notify_all(); 189 | } 190 | } 191 | 192 | template 193 | bool SafeQueue::TryPush(const T &a_elem) 194 | { 195 | std::lock_guard lk(m_mutex); 196 | 197 | bool rv = false; 198 | bool queueEmpty = m_theQueue.empty(); 199 | 200 | if (m_theQueue.size() < m_maximumSize) 201 | { 202 | m_theQueue.push(a_elem); 203 | rv = true; 204 | } 205 | 206 | if (queueEmpty) 207 | { 208 | // wake up threads waiting for stuff 209 | m_cond.notify_all(); 210 | } 211 | 212 | return rv; 213 | } 214 | 215 | template 216 | void SafeQueue::Pop(T &out_data) 217 | { 218 | std::unique_lock lk(m_mutex); 219 | 220 | while (m_theQueue.empty()) 221 | { 222 | m_cond.wait(lk); 223 | } 224 | 225 | bool queueFull = (m_theQueue.size() >= m_maximumSize) ? true : false; 226 | 227 | out_data = m_theQueue.front(); 228 | m_theQueue.pop(); 229 | 230 | if (queueFull) 231 | { 232 | // wake up threads waiting for stuff 233 | m_cond.notify_all(); 234 | } 235 | } 236 | 237 | template 238 | bool SafeQueue::TryPop(T &out_data) 239 | { 240 | std::lock_guard lk(m_mutex); 241 | 242 | bool rv = false; 243 | if (!m_theQueue.empty()) 244 | { 245 | bool queueFull = (m_theQueue.size() >= m_maximumSize) ? true : false; 246 | 247 | out_data = m_theQueue.front(); 248 | m_theQueue.pop(); 249 | 250 | if (queueFull) 251 | { 252 | // wake up threads waiting for stuff 253 | m_cond.notify_all(); 254 | } 255 | 256 | rv = true; 257 | } 258 | 259 | return rv; 260 | } 261 | 262 | template 263 | bool SafeQueue::TimedWaitPop(T &data, std::chrono::microseconds a_microsecs) 264 | { 265 | std::unique_lock lk(m_mutex); 266 | 267 | auto wakeUpTime = std::chrono::steady_clock::now() + a_microsecs; 268 | if (m_cond.wait_until(lk, wakeUpTime, 269 | [this](){return (m_theQueue.size() > 0);})) 270 | { 271 | // wait_until returns false if the predicate (3rd parameter) still 272 | // evaluates to false after the rel_time timeout expired 273 | // we are in this side of the if-clause because the queue is not empty 274 | // (so the 3rd parameter evaluated to true) 275 | bool queueFull = (m_theQueue.size() >= m_maximumSize) ? true : false; 276 | 277 | data = m_theQueue.front(); 278 | m_theQueue.pop(); 279 | 280 | if (queueFull) 281 | { 282 | // wake up threads waiting to insert things into the queue. 283 | // The queue used to be full, now it's not. 284 | m_cond.notify_all(); 285 | } 286 | 287 | return true; 288 | } 289 | else 290 | { 291 | // timed-out and the queue is still empty 292 | return false; 293 | } 294 | } 295 | 296 | #endif /* _SAFEQUEUEIMPL_H_ */ 297 | -------------------------------------------------------------------------------- /cpp/singleton.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2010-2014 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file singleton.h 23 | /// @brief A template to create singleton classes 24 | /// 25 | /// This file contains a template that can be used to turn your class into a 26 | /// singleton only by inheritance 27 | /// 28 | /// Your compiler must have support for c++11 29 | /// 30 | /// @author Faustino Frechilla 31 | /// @history 32 | /// Ref Who When What 33 | /// Faustino Frechilla 07-Apr-2010 Original development 34 | /// Faustino Frechilla 12-Mar-2014 Thread-safe using c++11 35 | /// @endhistory 36 | /// 37 | // ============================================================================ 38 | 39 | #ifndef _SINGLETON_H_ 40 | #define _SINGLETON_H_ 41 | 42 | #include 43 | 44 | /// @brief A templatised class for singletons 45 | /// Inherit from this class if you wish to make your class a singleton, so only 46 | /// an instance of it is created. The instance must be accessed using the 47 | /// Instance method. Example of usage: 48 | /// 49 | /// // using the template to "singletonize" your class 50 | /// class MySingleton: public Singleton 51 | /// { 52 | /// public: 53 | /// /* ... */ 54 | /// void MyMethod(); 55 | /// /* ... */ 56 | /// private: 57 | /// /* ... */ 58 | /// friend class Singleton; 59 | /// MySingleton(); 60 | /// ~MySingleton(); 61 | /// }; 62 | /// 63 | /// /* ... */ 64 | /// 65 | /// // accessing your brand new singleton 66 | /// MySingleton::Instance().MyMethod(); 67 | /// 68 | template 69 | class Singleton 70 | { 71 | public: 72 | /// @brief Gives access to the instance wrapped by this singleton 73 | /// @return a reference to the instance wrapped by the singleton 74 | static TClass& Instance() 75 | { 76 | if (m_instancePtr == 0) 77 | { 78 | // In the rare event that two threads come into this section only 79 | // one will acquire the spinlock and build the actual instance 80 | while(std::atomic_exchange_explicit(&m_lock, true, std::memory_order_acquire)) 81 | { 82 | ; // spin until acquired 83 | } 84 | 85 | if (m_instancePtr == 0) 86 | { 87 | // This is the thread that will build the real instance since 88 | // it hasn-t been instantiated yet 89 | m_instancePtr = new TClass(); 90 | } 91 | 92 | // Release spinlock 93 | std::atomic_store_explicit(&m_lock, false, std::memory_order_release); 94 | } 95 | 96 | return *m_instancePtr; 97 | } 98 | 99 | /// @brief Gives access to the singleton instance using a pointer 100 | /// @return a pointer to the instance wrapped by the singleton 101 | static TClass* GetPtr() 102 | { 103 | return &(Singleton::Instance()); 104 | } 105 | 106 | protected: 107 | Singleton(){}; 108 | virtual ~Singleton(){}; 109 | 110 | // the actual instance wrapped around the singleton 111 | static TClass *m_instancePtr; 112 | // a spinlock to make this singleton implementation thread-safe 113 | static std::atomic m_lock; 114 | }; 115 | 116 | template TClass* Singleton::m_instancePtr = 0; 117 | template std::atomic Singleton::m_lock(false); 118 | 119 | #endif /* _SINGLETON_H_ */ 120 | -------------------------------------------------------------------------------- /cpp/test/Makefile: -------------------------------------------------------------------------------- 1 | CC:=g++ 2 | CFLAGS:= -I.. -g -O0 -Wall -DDEBUG -D_REENTRANT 3 | CFLAGS+=-std=c++11 4 | LDFLAGS:= 5 | LIBS:=-pthread -std=c++11 6 | 7 | SOURCES = $(wildcard *.cpp) 8 | OBJS := $(SOURCES:.cpp=.o) 9 | BINARIES := $(patsubst %.cpp,%,$(SOURCES)) 10 | 11 | all: $(patsubst %.cpp,%,$(SOURCES)) 12 | 13 | $(BINARIES): %: %.o 14 | $(CC) $(LDFLAGS) $< -o $@ $(LIBS) 15 | 16 | $(OBJS): %.o : %.cpp 17 | $(CC) $(CFLAGS) -c $< -o $@ 18 | 19 | force: 20 | $(MAKE) clean_all 21 | $(MAKE) 22 | 23 | clean: 24 | rm -f $(OBJS) 25 | 26 | clean_all: 27 | rm -f $(OBJS); rm -f $(BINARIES) 28 | 29 | # Tell make that "all" etc. are phony targets, i.e. they should not be confused 30 | # with files of the same names. 31 | .PHONY: all clean clean_all force 32 | -------------------------------------------------------------------------------- /cpp/test/consumer_thread_test.cpp: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | /// @file consumer_thread_test.cpp 3 | /// @brief file to test the consumer thread class 4 | /// Compiling procedure: 5 | /// $ g++ -g -O0 -Wall -std=c++11 -D_REENTRANT -c consumer_thread_test.cpp 6 | /// $ g++ consumer_thread_test.o -o consumer_thread_test 7 | /// 8 | /// Expected output: 9 | /// 0ms: consumer1: Called to Init 10 | /// 0ms: consumer2: Called to Init2 11 | /// 999ms: main: producing: 0 12 | /// 999ms: consumer1: Consumed 0 13 | /// 999ms: main: producing: 1 14 | /// 999ms: consumer2: Consumed: 0 15 | /// 999ms: main: producing: 2 16 | /// 999ms: consumer2: Consumed: 1 17 | /// 999ms: consumer1: Consumed 1 18 | /// 999ms: consumer2: Consumed: 2 19 | /// 999ms: main: producing: 3 20 | /// 999ms: consumer1: Consumed 2 21 | /// 999ms: main: producing: 4 22 | /// 999ms: consumer2: Consumed: 3 23 | /// 999ms: consumer1: Consumed 3 24 | /// 999ms: main: producing: 5 25 | /// 999ms: consumer2: Consumed: 4 26 | /// 999ms: consumer1: Consumed 4 27 | /// 999ms: main: producing: 6 28 | /// 999ms: consumer2: Consumed: 5 29 | /// 999ms: consumer1: Consumed 5 30 | /// 999ms: main: producing: 7 31 | /// 999ms: consumer2: Consumed: 6 32 | /// 999ms: consumer1: Consumed 6 33 | /// 999ms: main: producing: 8 34 | /// 999ms: consumer2: Consumed: 7 35 | /// 999ms: consumer1: Consumed 7 36 | /// 999ms: main: producing: 9 37 | /// 999ms: consumer2: Consumed: 8 38 | /// 999ms: consumer1: Consumed 8 39 | /// 999ms: main: producing: 10 40 | /// 999ms: consumer2: Consumed: 9 41 | /// 999ms: consumer1: Consumed 9 42 | /// 999ms: main: producing: 11 43 | /// 999ms: consumer2: Consumed: 10 44 | /// 999ms: consumer1: Consumed 10 45 | /// 999ms: main: producing: 12 46 | /// 999ms: consumer2: Consumed: 11 47 | /// 999ms: consumer1: Consumed 11 48 | /// 999ms: main: producing: 13 49 | /// 999ms: consumer2: Consumed: 12 50 | /// 999ms: consumer1: Consumed 12 51 | /// 999ms: main: producing: 14 52 | /// 999ms: consumer2: Consumed: 13 53 | /// 999ms: consumer1: Consumed 13 54 | /// 999ms: main: producing: 15 55 | /// 999ms: consumer2: Consumed: 14 56 | /// 999ms: consumer1: Consumed 14 57 | /// 999ms: main: producing: 16 58 | /// 999ms: consumer2: Consumed: 15 59 | /// 999ms: consumer1: Consumed 15 60 | /// 999ms: main: producing: 17 61 | /// 999ms: consumer2: Consumed: 16 62 | /// 999ms: consumer1: Consumed 16 63 | /// 999ms: main: producing: 18 64 | /// 999ms: consumer2: Consumed: 17 65 | /// 999ms: main: producing: 19 66 | /// 999ms: consumer2: Consumed: 18 67 | /// 999ms: consumer1: Consumed 17 68 | /// 999ms: consumer2: Consumed: 19 69 | /// 999ms: consumer1: Consumed 18 70 | /// 999ms: consumer1: Consumed 19 71 | /// 1999ms: consumer1: Consumed 1000 72 | /// 1999ms: main: thread1 exited 73 | /// 2015ms: main: thread2 exited 74 | /// 2015ms: main: exiting ConsumerThreadTest::run 75 | // ============================================================================ 76 | 77 | #include 78 | #include 79 | #include // std::setw 80 | #include // std::stringstream 81 | #include 82 | 83 | #include "safe_queue.h" 84 | #include "consumer_thread.h" 85 | 86 | class ConsumerThreadTest 87 | { 88 | public: 89 | ConsumerThreadTest(): 90 | m_startTestTime(std::chrono::seconds(0)) 91 | {} 92 | 93 | virtual ~ConsumerThreadTest() 94 | {} 95 | 96 | void Init() 97 | { 98 | timedPrint("consumer1", "Called to Init"); 99 | } 100 | 101 | void Consume(int a_data) 102 | { 103 | std::stringstream strStream; 104 | strStream << "Consumed " << a_data; 105 | 106 | timedPrint("consumer1", strStream.str().c_str()); 107 | } 108 | 109 | void Init2() 110 | { 111 | timedPrint("consumer2", "Called to Init2"); 112 | } 113 | 114 | void Consume2(int a_data) 115 | { 116 | std::stringstream strStream; 117 | strStream << "Consumed: " << a_data; 118 | 119 | timedPrint("consumer2", strStream.str().c_str()); 120 | } 121 | 122 | int run(); 123 | 124 | private: 125 | std::chrono::system_clock::time_point m_startTestTime; 126 | std::mutex m_printMutex; 127 | 128 | void timedPrint(const char* a_who, const char* a_msg) 129 | { 130 | auto elapsed = std::chrono::system_clock::now() - m_startTestTime; 131 | 132 | std::unique_lock lk(m_printMutex); 133 | std::cout << std::setw(5) 134 | << std::chrono::duration_cast(elapsed).count() 135 | << "ms: " << a_who << ": " << a_msg << std::endl; 136 | std::cout.flush(); 137 | } 138 | }; 139 | 140 | int main() 141 | { 142 | ConsumerThreadTest theConsumerThreadTest; 143 | int theConsumerThreadTestResult; 144 | 145 | theConsumerThreadTestResult = theConsumerThreadTest.run(); 146 | 147 | return theConsumerThreadTestResult; 148 | } 149 | 150 | int ConsumerThreadTest::run() 151 | { 152 | m_startTestTime = std::chrono::system_clock::now(); 153 | 154 | // a consumer thread with the default queue size 155 | ConsumerThread thread1( 156 | std::bind(&ConsumerThreadTest::Consume, this, std::placeholders::_1), 157 | std::bind(&ConsumerThreadTest::Init, this)); 158 | 159 | // a consumer thread with queue size = 1 160 | ConsumerThread thread2( 161 | 1, 162 | std::bind(&ConsumerThreadTest::Consume2, this, std::placeholders::_1), 163 | std::bind(&ConsumerThreadTest::Init2, this)); 164 | 165 | std::this_thread::sleep_for(std::chrono::seconds(1)); 166 | 167 | for (int i = 0 ; i < 20 ; i++) 168 | { 169 | std::stringstream strStream; 170 | strStream << "producing: " << i; 171 | timedPrint("main", strStream.str().c_str()); 172 | 173 | thread1.Produce(i); 174 | thread2.Produce(i); 175 | } 176 | 177 | std::this_thread::sleep_for(std::chrono::seconds(1)); 178 | 179 | thread1.Produce(1000); 180 | 181 | thread1.Join(); 182 | timedPrint("main", "thread1 exited"); 183 | thread2.Join(); 184 | timedPrint("main", "thread2 exited"); 185 | 186 | // we joined the consumer threads. Calling to any of these functions now 187 | // will assert the test 188 | //thread1.Produce(1001); 189 | //thread2.Produce(1001); 190 | 191 | timedPrint("main", "exiting ConsumerThreadTest::run"); 192 | 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /cpp/test/lock_free_multiple_producers_q_test.cpp: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | /// @file lock_free_multiple_producers_q_test.cpp 3 | /// @brief Testing the circular array based lock free queue implementation 4 | /// Multiple producers implementation 5 | /// Compiling procedure: 6 | /// $ g++ -g -O0 -Wall -std=c++11 -D_REENTRANT -c lock_free_queue_test.cpp 7 | /// $ g++ lock_free_queue_test.o -o lock_free_queue_test -pthread -std=c++11 8 | /// 9 | /// Expected output: 10 | /// 0ms: main: About to create 3 consumers and 3 producers 11 | /// 0ms: main: About to call join on the producers... 12 | /// 1000ms: producer2: About to fill up the queue 13 | /// 1000ms: producer3: About to fill up the queue 14 | /// 1000ms: producer1: About to fill up the queue 15 | /// 1000ms: producer3: trying to push 2 more elements. Queue is full 16 | /// 1000ms: producer1: trying to push 2 more elements. Queue is full 17 | /// 1000ms: producer2: trying to push 2 more elements. Queue is full 18 | /// 3000ms: consumer2: About to empty out the queue 19 | /// 3000ms: consumer2: Sleeping for a second before popping the queue 20 | /// 3000ms: consumer3: About to empty out the queue 21 | /// 3000ms: consumer3: Sleeping for a second before popping the queue 22 | /// 3000ms: consumer1: About to empty out the queue 23 | /// 3000ms: consumer1: Sleeping for a second before popping the queue 24 | /// 4000ms: consumer2: Sleeping for a second before popping the queue 25 | /// 4000ms: producer2: Success!. Someone must have popped the queue 26 | /// 4000ms: consumer1: Sleeping for a second before popping the queue 27 | /// 4000ms: consumer3: Sleeping for a second before popping the queue 28 | /// 4000ms: producer1: Success!. Someone must have popped the queue 29 | /// 4000ms: producer3: Success!. Someone must have popped the queue 30 | /// 5000ms: consumer2: Sleeping for a second before popping the queue 31 | /// 5000ms: consumer1: Sleeping for a second before popping the queue 32 | /// 5000ms: producer1: Success!. Someone must have popped the queue 33 | /// 5000ms: producer1: Done! 34 | /// 5000ms: producer3: Success!. Someone must have popped the queue 35 | /// 5000ms: producer3: Done! 36 | /// 5000ms: consumer3: Sleeping for a second before popping the queue 37 | /// 5000ms: producer2: Success!. Someone must have popped the queue 38 | /// 5000ms: producer2: Done! 39 | /// 5000ms: main: Producer threads are done. About to sleep for 10 seconds... 40 | /// 6000ms: consumer2: Sleeping for a second before popping the queue 41 | /// 6000ms: consumer1: Sleeping for a second before popping the queue 42 | /// 6000ms: consumer3: Sleeping for a second before popping the queue 43 | /// 7000ms: consumer2: Sleeping for a second before popping the queue 44 | /// 7000ms: consumer1: Sleeping for a second before popping the queue 45 | /// 7000ms: consumer3: Sleeping for a second before popping the queue 46 | /// 8000ms: consumer2: About to pop another element 47 | /// 8000ms: consumer2: done popping 48 | /// 8000ms: consumer2: About to pop another element 49 | /// 8000ms: consumer2: done popping 50 | /// 8000ms: consumer2: done waiting on empty queue 51 | /// 8000ms: consumer2: Looping on an empty queue until someone pushes something 52 | /// 8000ms: consumer2: Done! 53 | /// 8000ms: consumer1: About to pop another element 54 | /// 8000ms: consumer1: done popping 55 | /// 8000ms: consumer1: About to pop another element 56 | /// 8000ms: consumer1: done popping 57 | /// 8000ms: consumer1: done waiting on empty queue 58 | /// 8000ms: consumer1: Looping on an empty queue until someone pushes something 59 | /// 8000ms: consumer1: Done! 60 | /// 8000ms: consumer3: About to pop another element 61 | ///15000ms: main: About to push something in the queue to let the consumers finish 62 | ///16001ms: consumer3: done popping 63 | ///16001ms: consumer3: About to pop another element 64 | ///16001ms: consumer3: done popping 65 | ///16001ms: consumer3: done waiting on empty queue 66 | ///16001ms: consumer3: Looping on an empty queue until someone pushes something 67 | ///16001ms: consumer3: Done! 68 | ///16001ms: main: Done! 69 | // ============================================================================ 70 | 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include // std::setw 79 | #include "lock_free_queue.h" 80 | 81 | #define QUEUE_SIZE 15 82 | 83 | const std::string CONSUMER1 = std::string("consumer1"); 84 | const std::string CONSUMER2 = std::string("consumer2"); 85 | const std::string CONSUMER3 = std::string("consumer3"); 86 | 87 | const std::string PRODUCER1 = std::string("producer1"); 88 | const std::string PRODUCER2 = std::string("producer2"); 89 | const std::string PRODUCER3 = std::string("producer3"); 90 | 91 | class ArrayLockFreeQueueTest 92 | { 93 | public: 94 | 95 | typedef ArrayLockFreeQueue< 96 | int, 97 | QUEUE_SIZE + 1, 98 | ArrayLockFreeQueueMultipleProducers> TestQueueType_t; 99 | 100 | ArrayLockFreeQueueTest(): 101 | m_queue(), 102 | m_startTestTime(std::chrono::seconds(0)), 103 | m_printMutex() 104 | {} 105 | 106 | virtual ~ArrayLockFreeQueueTest() 107 | {} 108 | 109 | int run() 110 | { 111 | int data; 112 | m_startTestTime = std::chrono::system_clock::now(); 113 | 114 | timedPrint("main", "About to create 3 consumers and 3 producers"); 115 | m_producerThread1.reset(new std::thread( 116 | std::bind(&ArrayLockFreeQueueTest::runProducer, this, PRODUCER1))); 117 | m_producerThread2.reset(new std::thread( 118 | std::bind(&ArrayLockFreeQueueTest::runProducer, this, PRODUCER2))); 119 | m_producerThread3.reset(new std::thread( 120 | std::bind(&ArrayLockFreeQueueTest::runProducer, this, PRODUCER3))); 121 | 122 | m_consumerThread1.reset(new std::thread( 123 | std::bind(&ArrayLockFreeQueueTest::runConsumer, this, CONSUMER1))); 124 | m_consumerThread2.reset(new std::thread( 125 | std::bind(&ArrayLockFreeQueueTest::runConsumer, this, CONSUMER2))); 126 | m_consumerThread3.reset(new std::thread( 127 | std::bind(&ArrayLockFreeQueueTest::runConsumer, this, CONSUMER3))); 128 | 129 | timedPrint("main", "About to call join on the producers..."); 130 | m_producerThread1->join(); 131 | m_producerThread2->join(); 132 | m_producerThread3->join(); 133 | 134 | timedPrint("main", "Producer threads are done. About to sleep for 10 seconds..."); 135 | std::this_thread::sleep_for(std::chrono::seconds(10)); 136 | 137 | timedPrint("main", "About to push something in the queue to let the consumers finish"); 138 | std::this_thread::sleep_for(std::chrono::seconds(1)); 139 | m_queue.push(0); 140 | m_queue.push(0); 141 | m_queue.push(0); 142 | 143 | m_consumerThread1->join(); 144 | m_consumerThread2->join(); 145 | m_consumerThread3->join(); 146 | 147 | assert(m_queue.pop(data) == false); 148 | 149 | timedPrint("main", "Done!"); 150 | 151 | return 0; 152 | } 153 | 154 | const TestQueueType_t& GetReferenceToQueue(){return m_queue;} 155 | //TestQueueType_t GetCopyOfQueue(){return m_queue;} 156 | 157 | private: 158 | TestQueueType_t m_queue; 159 | std::chrono::system_clock::time_point m_startTestTime; 160 | std::mutex m_printMutex; 161 | 162 | std::unique_ptr m_producerThread1; 163 | std::unique_ptr m_producerThread2; 164 | std::unique_ptr m_producerThread3; 165 | std::unique_ptr m_consumerThread1; 166 | std::unique_ptr m_consumerThread2; 167 | std::unique_ptr m_consumerThread3; 168 | 169 | void runProducer(const std::string &name) 170 | { 171 | std::this_thread::sleep_for(std::chrono::seconds(1)); 172 | 173 | timedPrint(name.c_str(), "About to fill up the queue"); 174 | for (int i = 0; i < QUEUE_SIZE/3; i++) 175 | { 176 | m_queue.push(i); 177 | } 178 | 179 | // wait for m_queue to be full 180 | while(m_queue.size() != QUEUE_SIZE); 181 | 182 | timedPrint(name.c_str(), "trying to push 2 more elements. Queue is full"); 183 | for (int i = 0; i < 2; i++) 184 | { 185 | while (m_queue.push(i) == false) 186 | ; 187 | timedPrint(name.c_str(), "Success!. Someone must have popped the queue"); 188 | } 189 | 190 | timedPrint(name.c_str(), "Done!"); 191 | } 192 | 193 | void runConsumer(const std::string &name) 194 | { 195 | int data; 196 | 197 | std::this_thread::sleep_for(std::chrono::seconds(3)); 198 | 199 | timedPrint(name.c_str(), "About to empty out the queue"); 200 | for (int i = 0; i < QUEUE_SIZE/3; i++) 201 | { 202 | timedPrint(name.c_str(), "Sleeping for a second before popping the queue"); 203 | std::this_thread::sleep_for(std::chrono::seconds(1)); 204 | while (m_queue.pop(data) == false) 205 | ; 206 | 207 | //assert(data == i); (multiple producers... strict order may not happen) 208 | } 209 | 210 | for (int i = 0; i < 2; i++) 211 | { 212 | timedPrint(name.c_str(), "About to pop another element"); 213 | while (m_queue.pop(data) == false) 214 | ; 215 | timedPrint(name.c_str(), "done popping"); 216 | 217 | //assert(data == i); (multiple producers... strict order may not happen) 218 | } 219 | 220 | timedPrint(name.c_str(), "done waiting on empty queue"); 221 | 222 | timedPrint(name.c_str(), "Looping on an empty queue until someone pushes something"); 223 | while (m_queue.pop(data) == false) 224 | ; 225 | timedPrint(name.c_str(), "Done!"); 226 | } 227 | 228 | void timedPrint(const char* a_who, const char* a_msg) 229 | { 230 | auto elapsed = std::chrono::system_clock::now() - m_startTestTime; 231 | 232 | std::unique_lock lk(m_printMutex); 233 | std::cout << std::setw(5) 234 | << std::chrono::duration_cast(elapsed).count() 235 | << "ms: " << a_who << ": " << a_msg << std::endl; 236 | std::cout.flush(); 237 | } 238 | }; 239 | 240 | int main(int /*argc*/, char** /*argv*/) 241 | { 242 | int multipleProducerResult; 243 | ArrayLockFreeQueueTest multipleProducerTest; 244 | 245 | multipleProducerResult = multipleProducerTest.run(); 246 | 247 | return multipleProducerResult; 248 | } 249 | -------------------------------------------------------------------------------- /cpp/test/lock_free_single_producer_q_test.cpp: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | /// @file lock_free_single_producer_q_test.cpp 3 | /// @brief Testing the circular array based lock free queue implementation 4 | /// (single producer implementation) 5 | /// Compiling procedure: 6 | /// $ g++ -g -O0 -Wall -std=c++11 -D_REENTRANT -c lock_free_queue_test.cpp 7 | /// $ g++ lock_free_queue_test.o -o lock_free_queue_test -pthread -std=c++11 8 | /// 9 | /// Expected output: 10 | /// 0ms: main: About to create the consumer and the producer 11 | /// 15ms: main: About to call join on the producer... 12 | /// 1015ms: producer: About to fill up the queue 13 | /// 1015ms: producer: trying to push 5 more elements. Queue is full 14 | /// 3015ms: consumer: About to empty out the queue 15 | /// 3015ms: consumer: Sleeping for a second before popping the queue 16 | /// 4016ms: producer: Success!. Someone must have popped the queue 17 | /// 4016ms: consumer: Sleeping for a second before popping the queue 18 | /// 5016ms: consumer: Sleeping for a second before popping the queue 19 | /// 5016ms: producer: Success!. Someone must have popped the queue 20 | /// 6016ms: consumer: Sleeping for a second before popping the queue 21 | /// 6016ms: producer: Success!. Someone must have popped the queue 22 | /// 7016ms: consumer: Sleeping for a second before popping the queue 23 | /// 7016ms: producer: Success!. Someone must have popped the queue 24 | /// 8016ms: consumer: Sleeping for a second before popping the queue 25 | /// 8016ms: producer: Success!. Someone must have popped the queue 26 | /// 8016ms: producer: Done! 27 | /// 8016ms: main: Producer thread is done. About to sleep for 10 seconds... 28 | /// 9016ms: consumer: Sleeping for a second before popping the queue 29 | /// 10016ms: consumer: Sleeping for a second before popping the queue 30 | /// 11016ms: consumer: Sleeping for a second before popping the queue 31 | /// 12016ms: consumer: Sleeping for a second before popping the queue 32 | /// 13016ms: consumer: About to pop another element 33 | /// 13016ms: consumer: done popping 34 | /// 13016ms: consumer: About to pop another element 35 | /// 13016ms: consumer: done popping 36 | /// 13016ms: consumer: About to pop another element 37 | /// 13016ms: consumer: done popping 38 | /// 13016ms: consumer: About to pop another element 39 | /// 13016ms: consumer: done popping 40 | /// 13016ms: consumer: About to pop another element 41 | /// 13016ms: consumer: done popping 42 | /// 13016ms: consumer: done waiting on empty queue 43 | /// 13016ms: consumer: Looping on an empty queue until someone pushes something 44 | /// 18017ms: main: About to push something in the queue to let the consumer finish 45 | /// 19017ms: consumer: Done! 46 | /// 19017ms: main: Done! 47 | // ============================================================================ 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include // std::setw 57 | #include "lock_free_queue.h" 58 | 59 | #define QUEUE_SIZE 15 60 | 61 | class ArrayLockFreeQueueTest 62 | { 63 | public: 64 | 65 | typedef ArrayLockFreeQueue< 66 | int, 67 | QUEUE_SIZE + 1, 68 | ArrayLockFreeQueueSingleProducer> TestQueueType_t; 69 | 70 | ArrayLockFreeQueueTest(): 71 | m_queue(), 72 | m_startTestTime(std::chrono::seconds(0)), 73 | m_printMutex() 74 | {} 75 | 76 | virtual ~ArrayLockFreeQueueTest() 77 | {} 78 | 79 | int run() 80 | { 81 | m_startTestTime = std::chrono::system_clock::now(); 82 | 83 | timedPrint("main", "About to create the consumer and the producer"); 84 | m_producerThread.reset(new std::thread(std::bind(&ArrayLockFreeQueueTest::runProducer, this))); 85 | m_consumerThread.reset(new std::thread(std::bind(&ArrayLockFreeQueueTest::runConsumer, this))); 86 | 87 | timedPrint("main", "About to call join on the producer..."); 88 | m_producerThread->join(); 89 | 90 | timedPrint("main", "Producer thread is done. About to sleep for 10 seconds..."); 91 | std::this_thread::sleep_for(std::chrono::seconds(10)); 92 | 93 | timedPrint("main", "About to push something in the queue to let the consumer finish"); 94 | std::this_thread::sleep_for(std::chrono::seconds(1)); 95 | m_queue.push(0); 96 | 97 | m_consumerThread->join(); 98 | timedPrint("main", "Done!"); 99 | 100 | return 0; 101 | } 102 | 103 | const TestQueueType_t& GetReferenceToQueue(){return m_queue;} 104 | //TestQueueType_t GetCopyOfQueue(){return m_queue;} 105 | 106 | private: 107 | TestQueueType_t m_queue; 108 | std::chrono::system_clock::time_point m_startTestTime; 109 | std::mutex m_printMutex; 110 | 111 | std::unique_ptr m_producerThread; 112 | std::unique_ptr m_consumerThread; 113 | 114 | void runProducer() 115 | { 116 | std::this_thread::sleep_for(std::chrono::seconds(1)); 117 | 118 | timedPrint("producer", "About to fill up the queue"); 119 | for (int i = 0; i < QUEUE_SIZE; i++) 120 | { 121 | m_queue.push(i); 122 | } 123 | 124 | // m_queue should be full 125 | assert(m_queue.size() == QUEUE_SIZE); 126 | 127 | timedPrint("producer", "trying to push 5 more elements. Queue is full"); 128 | for (int i = 0; i < 5; i++) 129 | { 130 | while (m_queue.push(i) == false) 131 | ; 132 | timedPrint("producer", "Success!. Someone must have popped the queue"); 133 | } 134 | 135 | timedPrint("producer", "Done!"); 136 | } 137 | 138 | void runConsumer() 139 | { 140 | int data; 141 | 142 | std::this_thread::sleep_for(std::chrono::seconds(3)); 143 | 144 | timedPrint("consumer", "About to empty out the queue"); 145 | for (int i = 0; i < QUEUE_SIZE; i++) 146 | { 147 | timedPrint("consumer", "Sleeping for a second before popping the queue"); 148 | std::this_thread::sleep_for(std::chrono::seconds(1)); 149 | while (m_queue.pop(data) == false) 150 | ; 151 | 152 | assert(data == i); 153 | } 154 | 155 | for (int i = 0; i < 5; i++) 156 | { 157 | timedPrint("consumer", "About to pop another element"); 158 | assert(m_queue.pop(data) == true); 159 | timedPrint("consumer", "done popping"); 160 | 161 | assert(data == i); 162 | } 163 | 164 | assert(m_queue.pop(data) == false); 165 | timedPrint("consumer", "done waiting on empty queue"); 166 | 167 | timedPrint("consumer", "Looping on an empty queue until someone pushes something"); 168 | while (m_queue.pop(data) == false) 169 | ; 170 | timedPrint("consumer", "Done!"); 171 | } 172 | 173 | void timedPrint(const char* a_who, const char* a_msg) 174 | { 175 | auto elapsed = std::chrono::system_clock::now() - m_startTestTime; 176 | 177 | std::unique_lock lk(m_printMutex); 178 | std::cout << std::setw(5) 179 | << std::chrono::duration_cast(elapsed).count() 180 | << "ms: " << a_who << ": " << a_msg << std::endl; 181 | std::cout.flush(); 182 | } 183 | }; 184 | 185 | int main(int /*argc*/, char** /*argv*/) 186 | { 187 | int singleProducerResult; 188 | ArrayLockFreeQueueTest singleProducerTest; 189 | 190 | singleProducerResult = singleProducerTest.run(); 191 | 192 | return singleProducerResult; 193 | } 194 | -------------------------------------------------------------------------------- /cpp/test/safe_queue_test.cpp: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | /// @file safe_queue_test.cpp 3 | /// @brief Testing the safe queue implementation 4 | /// Compiling procedure: 5 | /// $ g++ -g -O0 -Wall -std=c++11 -D_REENTRANT -c safe_queue_test.cpp 6 | /// $ g++ safe_queue_test.o -o safe_queue_test 7 | /// 8 | /// Expected output: 9 | /// 0ms: main: About to create the consumer and the producer 10 | /// 0ms: main: About to call join on the producer... 11 | /// 999ms: producer: About to fill up the queue 12 | /// 999ms: producer: trying to push 5 more elements. Queue is full 13 | /// 2999ms: consumer: About to empty out the queue 14 | /// 2999ms: consumer: Sleeping for a second before popping the queue 15 | /// 3999ms: consumer: Sleeping for a second before popping the queue 16 | /// 3999ms: producer: Woken up. Someone must have popped the queue 17 | /// 4999ms: consumer: Sleeping for a second before popping the queue 18 | /// 4999ms: producer: Woken up. Someone must have popped the queue 19 | /// 5999ms: consumer: Sleeping for a second before popping the queue 20 | /// 5999ms: producer: Woken up. Someone must have popped the queue 21 | /// 6999ms: consumer: Sleeping for a second before popping the queue 22 | /// 6999ms: producer: Woken up. Someone must have popped the queue 23 | /// 7999ms: consumer: Sleeping for a second before popping the queue 24 | /// 7999ms: producer: Woken up. Someone must have popped the queue 25 | /// 7999ms: producer: Done! 26 | /// 7999ms: main: Producer thread is done. About to sleep for 10 seconds... 27 | /// 8999ms: consumer: Sleeping for a second before popping the queue 28 | /// 9999ms: consumer: Sleeping for a second before popping the queue 29 | /// 10999ms: consumer: Sleeping for a second before popping the queue 30 | /// 11999ms: consumer: Sleeping for a second before popping the queue 31 | /// 12998ms: consumer: About to pop an element with TimedWaitPop 32 | /// 12998ms: consumer: done popping an element with TimedWaitPop 33 | /// 12998ms: consumer: About to pop an element with TimedWaitPop 34 | /// 12998ms: consumer: done popping an element with TimedWaitPop 35 | /// 12998ms: consumer: About to pop an element with TimedWaitPop 36 | /// 12998ms: consumer: done popping an element with TimedWaitPop 37 | /// 12998ms: consumer: About to pop an element with TimedWaitPop 38 | /// 12998ms: consumer: done popping an element with TimedWaitPop 39 | /// 12998ms: consumer: About to pop an element with TimedWaitPop 40 | /// 12998ms: consumer: done popping an element with TimedWaitPop 41 | /// 12998ms: consumer: Waiting one second on an empty queue for a second 42 | /// 14014ms: consumer: done waiting on empty queue 43 | /// 14014ms: consumer: Waiting on an empty queue until someone pushes something 44 | /// 18029ms: main: About to push something in the queue to let the consumer finish 45 | /// 19029ms: consumer: Done! 46 | /// 19029ms: main: Done! 47 | // ============================================================================ 48 | 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include // std::setw 57 | #include "safe_queue.h" 58 | 59 | #define QUEUE_SIZE 10 60 | 61 | class SafeQueueTest 62 | { 63 | public: 64 | SafeQueueTest(): 65 | m_queue(QUEUE_SIZE), 66 | m_startTestTime(std::chrono::seconds(0)), 67 | m_printMutex() 68 | {} 69 | 70 | virtual ~SafeQueueTest() 71 | {} 72 | 73 | int run() 74 | { 75 | m_startTestTime = std::chrono::system_clock::now(); 76 | 77 | copyConstructorTest(); 78 | moveContructorTest(); 79 | 80 | timedPrint("main", "About to create the consumer and the producer"); 81 | m_producerThread.reset(new std::thread(std::bind(&SafeQueueTest::runProducer, this))); 82 | m_consumerThread.reset(new std::thread(std::bind(&SafeQueueTest::runConsumer, this))); 83 | 84 | timedPrint("main", "About to call join on the producer..."); 85 | m_producerThread->join(); 86 | 87 | timedPrint("main", "Producer thread is done. About to sleep for 10 seconds..."); 88 | std::this_thread::sleep_for(std::chrono::seconds(10)); 89 | 90 | timedPrint("main", "About to push something in the queue to let the consumer finish"); 91 | std::this_thread::sleep_for(std::chrono::seconds(1)); 92 | m_queue.Push(0); 93 | 94 | m_consumerThread->join(); 95 | timedPrint("main", "Done!"); 96 | 97 | return 0; 98 | } 99 | 100 | const SafeQueue& GetReferenceToQueue(){return m_queue;} 101 | SafeQueue GetCopyOfQueue(){return m_queue;} 102 | 103 | private: 104 | SafeQueue m_queue; 105 | std::chrono::system_clock::time_point m_startTestTime; 106 | std::mutex m_printMutex; 107 | 108 | std::unique_ptr m_producerThread; 109 | std::unique_ptr m_consumerThread; 110 | 111 | void runProducer() 112 | { 113 | std::this_thread::sleep_for(std::chrono::seconds(1)); 114 | 115 | timedPrint("producer", "About to fill up the queue"); 116 | for (int i = 0; i < QUEUE_SIZE; i++) 117 | { 118 | m_queue.Push(i); 119 | } 120 | 121 | // m_queue should be full 122 | assert(m_queue.TryPush(11) == false); 123 | 124 | timedPrint("producer", "trying to push 5 more elements. Queue is full"); 125 | for (int i = 0; i < 5; i++) 126 | { 127 | m_queue.Push(i); 128 | timedPrint("producer", "Woken up. Someone must have popped the queue"); 129 | } 130 | 131 | timedPrint("producer", "Done!"); 132 | } 133 | 134 | void runConsumer() 135 | { 136 | int data; 137 | 138 | std::this_thread::sleep_for(std::chrono::seconds(3)); 139 | 140 | timedPrint("consumer", "About to empty out the queue"); 141 | for (int i = 0; i < QUEUE_SIZE; i++) 142 | { 143 | timedPrint("consumer", "Sleeping for a second before popping the queue"); 144 | std::this_thread::sleep_for(std::chrono::seconds(1)); 145 | m_queue.Pop(data); 146 | 147 | assert(data == i); 148 | } 149 | 150 | for (int i = 0; i < 5; i++) 151 | { 152 | timedPrint("consumer", "About to pop an element with TimedWaitPop"); 153 | assert( 154 | m_queue.TimedWaitPop(data, std::chrono::microseconds(100)) == true); 155 | timedPrint("consumer", "done popping an element with TimedWaitPop"); 156 | 157 | assert(data == i); 158 | } 159 | 160 | timedPrint("consumer", "Waiting one second on an empty queue for a second"); 161 | assert( 162 | m_queue.TimedWaitPop(data, std::chrono::seconds(1)) == false); 163 | timedPrint("consumer", "done waiting on empty queue"); 164 | 165 | timedPrint("consumer", "Waiting on an empty queue until someone pushes something"); 166 | m_queue.Pop(data); 167 | timedPrint("consumer", "Done!"); 168 | } 169 | 170 | ////////////////////////////// 171 | // copy constructor and operator= tests 172 | // 173 | //TODO definitely improvable! 174 | // 175 | void copyConstructorTest() 176 | { 177 | // tmp variables for testing purposes 178 | int a,b; 179 | 180 | // copy constructor 181 | SafeQueue q1(this->GetReferenceToQueue()); 182 | assert(q1.IsEmpty()); 183 | 184 | // copy constructor 185 | SafeQueue q2 = q1; 186 | assert(q2.IsEmpty()); 187 | 188 | q2 = q2; // operator= does nothing 189 | q2.Push(1); 190 | assert(!q2.IsEmpty()); 191 | 192 | // constructor 193 | SafeQueue q3; 194 | 195 | q3 = q2; // operator= copies things 196 | assert(!q3.IsEmpty()); 197 | 198 | q2.Pop(a); 199 | q3.Pop(b); 200 | assert(a == b); 201 | } 202 | 203 | ////////////////////////////// 204 | // move constructor and move assignment tests 205 | // 206 | //TODO definitely improvable! 207 | // 208 | void moveContructorTest() 209 | { 210 | //TODO definitely improvable! 211 | 212 | // constructor: a brand new instance of a queue 213 | SafeQueue q1; 214 | 215 | // move assignment test: Copy constructor + move assignment get called 216 | q1 = this->GetCopyOfQueue(); 217 | assert(q1.IsEmpty()); 218 | 219 | // move constructor test: Copy constructor + move constructor get called 220 | const SafeQueue q2(std::move(this->GetCopyOfQueue())); 221 | assert(q2.IsEmpty()); 222 | } 223 | 224 | void timedPrint(const char* a_who, const char* a_msg) 225 | { 226 | auto elapsed = std::chrono::system_clock::now() - m_startTestTime; 227 | 228 | std::unique_lock lk(m_printMutex); 229 | std::cout << std::setw(5) 230 | << std::chrono::duration_cast(elapsed).count() 231 | << "ms: " << a_who << ": " << a_msg << std::endl; 232 | std::cout.flush(); 233 | } 234 | }; 235 | 236 | int main(int /*argc*/, char** /*argv*/) 237 | { 238 | SafeQueueTest theSafeQueueTest; 239 | int theSafeQueueTestResult; 240 | 241 | theSafeQueueTestResult = theSafeQueueTest.run(); 242 | 243 | return theSafeQueueTestResult; 244 | } 245 | -------------------------------------------------------------------------------- /cpp/test/singleton_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "singleton.h" 4 | 5 | // compilation: 6 | // $ g++ -g -O0 -Wall -std=c++11 -D_REENTRANT singleton_test.cpp -o singleton_test 7 | 8 | class MySingleton : 9 | public Singleton 10 | { 11 | public: 12 | int a; 13 | int b; 14 | 15 | private: 16 | friend class Singleton; 17 | 18 | MySingleton(): a(1), b(2) 19 | {} 20 | virtual ~MySingleton() {} 21 | }; 22 | 23 | class SingletonTest 24 | { 25 | public: 26 | // TODO check thread safety of initialisation 27 | int run(); 28 | 29 | private: 30 | }; 31 | 32 | int SingletonTest::run() 33 | { 34 | std::cout << "A: " << MySingleton::Instance().a << std::endl; 35 | std::cout << "B: " << MySingleton::GetPtr()->b << std::endl; 36 | 37 | (MySingleton::Instance().a)++; 38 | (MySingleton::Instance().b)++; 39 | 40 | std::cout << "A: " << ++(MySingleton::GetPtr()->a) << std::endl; 41 | std::cout << "B: " << ++(MySingleton::Instance().b) << std::endl; 42 | 43 | (MySingleton::Instance().a)--; 44 | (MySingleton::Instance().b)--; 45 | 46 | std::cout << "A: " << MySingleton::Instance().a << std::endl; 47 | std::cout << "B: " << MySingleton::Instance().b << std::endl; 48 | 49 | MySingleton::Instance().a = 15; 50 | MySingleton::Instance().b = 25; 51 | 52 | std::cout << "A: " << MySingleton::GetPtr()->a << std::endl; 53 | std::cout << "B: " << MySingleton::GetPtr()->b << std::endl; 54 | 55 | assert(MySingleton::GetPtr() == &(MySingleton::Instance())); 56 | 57 | return 0; 58 | } 59 | 60 | int main() 61 | { 62 | SingletonTest theTest; 63 | int theSingletonTestResult; 64 | 65 | theSingletonTestResult = theTest.run(); 66 | 67 | return theSingletonTestResult; 68 | } -------------------------------------------------------------------------------- /cpp/test/vtimer_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "vtimer.h" 3 | 4 | // compilation: 5 | // $ g++ -g -O0 -Wall -std=c++11 -D_REENTRANT vtimer_test.cpp -o vtimer_test 6 | 7 | class VTimerTest 8 | { 9 | public: 10 | VTimerTest() 11 | {} 12 | 13 | ~VTimerTest() 14 | {} 15 | 16 | void Callback(uint32_t a_currentTime) 17 | { 18 | std::cout << "Callback called at " << 19 | static_cast(a_currentTime) << std::endl; 20 | } 21 | 22 | int run(); 23 | 24 | private: 25 | }; 26 | 27 | void GlobalCallback(uint32_t a_currentTime) 28 | { 29 | std::cout << "Global Callback called at " << 30 | static_cast(a_currentTime) << std::endl; 31 | } 32 | 33 | int VTimerTest::run() 34 | { 35 | VTimer virtual_timer( 36 | std::bind(&VTimerTest::Callback, this, std::placeholders::_1), 37 | 10); // period 38 | 39 | // init at 1. Callback should get called on 11 or bigger 40 | virtual_timer.Update(1); 41 | virtual_timer.Update(3); 42 | // time should not go backwards, but the virtual time does not care as long as it 43 | // is bigger than 0 44 | virtual_timer.Update(2); 45 | virtual_timer.Update(3); 46 | // about to get called 47 | virtual_timer.Update(10); 48 | // calback should get called. Next expiration time 21! 49 | virtual_timer.Update(11); 50 | // calback should get called. Next expiration time 31! 51 | virtual_timer.Update(21); 52 | // calback should get called. Next expiration time 44! 53 | virtual_timer.Update(34); 54 | // EXpiration time is calculated from the latest time received (34) 55 | virtual_timer.Update(41); 56 | // No Callback call 57 | virtual_timer.Update(43); 58 | // Callback!!! 59 | virtual_timer.Update(44); 60 | // No callback until 54... 61 | virtual_timer.Update(44); 62 | // No callback until 54... 63 | virtual_timer.Update(44); 64 | // No callback until 54... 65 | virtual_timer.Update(53); 66 | 67 | // this timer should call the callback EVERY single call to update 68 | // except when it is called with time set to 0, the first time it's called 69 | // or when the timer goes backwards 70 | VTimer virtual_timer2( 71 | std::bind(&GlobalCallback, std::placeholders::_1), 72 | 0); // period 73 | // no call 74 | virtual_timer2.Update(0); 75 | // no call 76 | virtual_timer2.Update(0); 77 | // call! 78 | virtual_timer2.Update(1); 79 | // no call! 80 | virtual_timer2.Update(0); 81 | // call! 82 | virtual_timer2.Update(1); 83 | // call! 84 | virtual_timer2.Update(2); 85 | // call! 86 | virtual_timer2.Update(2); 87 | // no call! 88 | virtual_timer2.Update(1); 89 | // call! 90 | virtual_timer2.Update(2); 91 | 92 | return 0; 93 | } 94 | 95 | int main() 96 | { 97 | VTimerTest theTest; 98 | int theVTimerTestResult; 99 | 100 | theVTimerTestResult = theTest.run(); 101 | 102 | return theVTimerTestResult; 103 | } -------------------------------------------------------------------------------- /cpp/vtimer.h: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // Copyright (c) 2009-2013 Faustino Frechilla 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | // 22 | /// @file vtimer.h 23 | /// @brief This file contains a virtual timer class. 24 | /// 25 | /// This timer calls a callback function when a timeout expires. It does not 26 | /// maintain the current time by itself, an object of this class needs 27 | /// to be updated with the current time periodically to ensure the callback 28 | /// is called as expected. 29 | /// An object of this class is not thead-safe by itself. If used in a 30 | /// multi-thread system it will need to be protected from outside 31 | /// 32 | /// Your compiler must have support for c++11. Example of usage: 33 | /// 34 | /// void MyCallback(uint32_t a_currentTime); 35 | /// /* ... */ 36 | /// 37 | /// Timer virtual_timer( 38 | /// std::bind(&GlobalCallback, std::placeholders::_1), 15); 39 | /// virtual_timer.Update(0); 40 | /// virtual_timer.Update(30); 41 | /// /* ... */ 42 | /// 43 | /// @author Faustino Frechilla 44 | /// @history 45 | /// Ref Who When What 46 | /// Faustino Frechilla 12-Jun-2009 Original development 47 | /// Faustino Frechilla 06-Jul-2013 Ported to c++11. Templates 48 | /// @endhistory 49 | /// 50 | // ============================================================================ 51 | 52 | #ifndef _VTIMER_H_ 53 | #define _VTIMER_H_ 54 | 55 | #include // types (uint64_t...) 56 | #include // std::function 57 | #include 58 | 59 | /// @brief a Virtual Timer 60 | /// Calls a callback function when a timeout expires. It does not 61 | /// have a real timer by itself, an object of this class needs to be updated 62 | /// with the current time periodically to ensure the callback is called as 63 | /// expected. 64 | /// 65 | /// This class is templatized so the time type depends on the particular 66 | /// instantiation. Bear in mind TIME_TYPE must have at least support 67 | /// for copy constructor, operator=, operator>=, operator== and operator+ 68 | /// and it should also be able to be initialised with a 0: "TIME_TYPE obj(0)" 69 | template 70 | class VTimer 71 | { 72 | public: 73 | typedef std::function VTimerCallback_t; 74 | 75 | /// @brief constructor of a virtual timer 76 | /// @param a_callback Callback function that will get called on expiration 77 | /// @param period of time between calls. It must be greater or equal to 0 78 | VTimer(VTimerCallback_t a_callback, TIME_TYPE a_period): 79 | m_callback(a_callback), 80 | m_nextExpiryTime(0), 81 | m_period(a_period) 82 | { 83 | assert(a_period >= 0); 84 | } 85 | 86 | /// @brief destructor 87 | virtual ~VTimer() 88 | {} 89 | 90 | /// @brief update the current time 91 | /// If the timeout expires the callback function will get called from the 92 | /// same thread that updated the current time with the current time 93 | /// The expiration time is calculated the first time this function 94 | /// is called based on the parameter "a_current". (the first expiration 95 | /// time will be set to a_current + m_period) 96 | /// 97 | /// The callback won't get called under the following circumstances: 98 | /// - The first time Update is called the internal attributes are 99 | /// initialised (but the callback is not called) 100 | /// - When "a_currentTime" is set to 0 the callback won't ever get called 101 | /// - If "a_currentTime" goes backwards in time 102 | /// @param a_currentTime 103 | inline void Update(TIME_TYPE a_currentTime) 104 | { 105 | assert(a_currentTime >= 0); 106 | 107 | if (m_nextExpiryTime == 0) 108 | { 109 | if ((a_currentTime + m_period) == 0) 110 | { 111 | // corner case. Period is "0" and Update is initialised with 112 | // time 0. m_nextExpiryTime is initalised to 1 113 | m_nextExpiryTime = 1; 114 | } 115 | else 116 | { 117 | m_nextExpiryTime = a_currentTime + m_period; 118 | } 119 | } 120 | else if (a_currentTime >= m_nextExpiryTime) 121 | { 122 | m_nextExpiryTime = a_currentTime + m_period; 123 | m_callback(a_currentTime); 124 | } 125 | } 126 | 127 | private: 128 | /// a pointer to the callback function 129 | VTimerCallback_t m_callback; 130 | 131 | /// timestamp of the next time the callback function will get called 132 | TIME_TYPE m_nextExpiryTime; 133 | 134 | /// the timeout period 135 | TIME_TYPE m_period; 136 | }; 137 | 138 | #endif /* _VTIMER_H_ */ 139 | -------------------------------------------------------------------------------- /scripts/animated_graph.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | usage: %(scriptName)s [MAX_DATA_COUNT] 5 | 6 | draw a live graph based on random data generated by a producer thread 7 | The graph will have MAX_DATA_COUNT elements. New elements will replace older 8 | ones 9 | """ 10 | 11 | # Copyright (C) 2015 Faustino Frechilla (frechilla@gmail.com) 12 | # 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy 14 | # of this software and associated documentation files (the "Software"), to 15 | # deal in the Software without restriction, including without limitation the 16 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 17 | # sell copies of the Software, and to permit persons to whom the Software is 18 | # furnished to do so, subject to the following conditions: 19 | # 20 | # The above copyright notice and this permission notice shall be included in 21 | # all copies or substantial portions of the Software. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 24 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 29 | # IN THE SOFTWARE. 30 | 31 | import time 32 | import sys 33 | import threading, Queue 34 | import random 35 | 36 | import matplotlib.pyplot as plt 37 | import matplotlib.animation as animation 38 | 39 | # refresh animation every... 40 | # 41 | REFRESH_MSECS = 250 42 | 43 | # default MAX_DATA_COUNT 44 | # 45 | DEFAULT_MAX_DATA_COUNT = 10 46 | 47 | rangen = None 48 | data_queue1 = None 49 | data_queue2 = None 50 | yar1 = [] 51 | yar2 = [] 52 | xar = [] 53 | 54 | def usage(): 55 | """Prints the usage info text extracted from this script's documentation 56 | """ 57 | print (__doc__ % {'scriptName' : sys.argv[0]}).lstrip() 58 | 59 | def data_generator(q1, q2): 60 | while(True): 61 | try: 62 | q1.put(rangen.randint(0,100)) 63 | q2.put(rangen.uniform(0,100)) 64 | except Exception, msg: 65 | print "Producer thread: %s" % (msg) 66 | # produce data once every REFRESH_MSECS + 100ms 67 | # *a way to test what happens if producer and consumer are not in sync) 68 | time.sleep((REFRESH_MSECS/1000) + 0.1) 69 | 70 | def animate_graph(i): 71 | if (data_queue1 and not data_queue1.empty() and data_queue2 and not data_queue2.empty()): 72 | if(len(xar) == 0): 73 | xar.append(0) 74 | else: 75 | if (len(xar) > max_count): 76 | #xar.pop(0) 77 | #ax.set_xlim(xar[0], xar[-1]) 78 | yar1.pop(0) 79 | yar2.pop(0) 80 | else: 81 | xar.append(xar[-1] + 1) 82 | yar1.append(data_queue1.get(False)) 83 | yar2.append(data_queue2.get(False)) 84 | yar1_text.set_text('line1: %02d' % yar1[-1]) 85 | yar2_text.set_text('line2: %05.2f' % yar2[-1]) 86 | #ax.relim() 87 | #ax.autoscale_view() 88 | print "%02d %05.2f" % (yar1[-1], yar2[-1]) 89 | line1.set_data(xar, yar1) 90 | line2.set_data(xar, yar2) 91 | else: 92 | # nothing to be done for now... 93 | pass 94 | return line1, line2, yar1_text, yar2_text 95 | 96 | def init_graph(): 97 | ax.xaxis.set_ticklabels([]) 98 | ax.xaxis.set_ticks([]) 99 | ax.yaxis.set_ticks([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) 100 | #ax.set_xlim(0, max_count) 101 | yar1_text.set_text('') 102 | yar2_text.set_text('') 103 | line1.set_data([], []) 104 | line2.set_data([], []) 105 | return line1, line2, yar1_text, yar2_text 106 | 107 | if __name__ == '__main__': 108 | 109 | # process command line parameters 110 | # 111 | if (len(sys.argv) < 2): 112 | max_count = DEFAULT_MAX_DATA_COUNT 113 | print "maximum number of elements set to %d" % (DEFAULT_MAX_DATA_COUNT) 114 | else: 115 | try: 116 | max_count = int(sys.argv[1]) 117 | except: 118 | print "Invalid maximum number of elements in graph" 119 | usage() 120 | sys.exit() 121 | 122 | # random generator initilisation 123 | # 124 | try: 125 | rangen = random.SystemRandom() 126 | except NotImplementedError, msg: 127 | print 'Warning: random.SystemRandom is not implemented in this OS' 128 | rangen = random 129 | finally: 130 | # Initialize the basic random number generator with current system time 131 | # no matter which random generator we are using 132 | rangen.seed() 133 | 134 | data_queue1 = Queue.Queue() 135 | data_queue2 = Queue.Queue() 136 | datathread = threading.Thread(target = data_generator, args = (data_queue1, data_queue2)) 137 | datathread.setDaemon(True) 138 | datathread.start() 139 | 140 | fig = plt.figure() 141 | #ax = fig.add_subplot(111, aspect='equal', autoscale_on = False, xlim=(0, max_count), ylim=(0, 100), ylabel = "%") 142 | ax = plt.axes(xlim=(0, max_count), ylim=(0, 100), ylabel = "my label") 143 | #fig, ax = plt.subplots() 144 | line1, = ax.plot([], [], lw=2, label="line1", color='blue') 145 | line2, = ax.plot([], [], lw=1, label="line2", color='green') 146 | 147 | yar1_text = ax.text(.02, .96, '', transform=ax.transAxes, color='blue', family='monospace') 148 | yar2_text = ax.text(.02, .91, '', transform=ax.transAxes, color='green', family='monospace') 149 | 150 | # init graph with some data 151 | #yar1=[1, 2, 56, 3] 152 | #yar2=[5, 6, 0, 73] 153 | #xar=range(0, len(yar1)) 154 | 155 | print "-" * 79 156 | 157 | ani = animation.FuncAnimation(fig, animate_graph, interval=REFRESH_MSECS, init_func=init_graph, blit=True) 158 | # loc=2 --> upper left. 159 | # See http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.legend 160 | #plt.legend([line1, line2], ["CPU", "MEM"], loc=2) 161 | #plt.legend(loc=2) 162 | plt.grid(True) 163 | plt.show() 164 | 165 | -------------------------------------------------------------------------------- /scripts/bash/.bash_aliases.sh: -------------------------------------------------------------------------------- 1 | # this is a shortcut function to look for text in .h, .c, .cc and .cpp files 2 | # using the "find" utility 3 | # 4 | #usage: c_srcsearch [-i] [directory] string-to-search 5 | # -i: optional parameter to activate case insensitive search 6 | # directory: optional parameter. c_srcsearch will look for 7 | # string-to-search in this directory 8 | # 9 | c_srcsearch() 10 | { 11 | OPT_CASE="" 12 | OPT_DIR="" 13 | OPT_STR="" 14 | if [[ $# -eq 3 && $1 == "-i" && -d $2 ]]; then 15 | OPT_CASE="-i" 16 | OPT_DIR=$2 17 | OPT_STR=$3 18 | elif [[ $# -eq 2 && $1 == "-i" ]]; then 19 | OPT_CASE="-i" 20 | OPT_DIR="." 21 | OPT_STR=$2 22 | elif [[ $# -eq 2 && -d $1 ]]; then 23 | OPT_CASE="" 24 | OPT_DIR=$1 25 | OPT_STR=$2 26 | elif [[ $# -eq 1 && $1 != "-i" ]]; then 27 | OPT_CASE="" 28 | OPT_DIR="." 29 | OPT_STR=$1 30 | fi 31 | 32 | if [[ $OPT_CASE || $OPT_DIR || $OPT_STR ]]; then 33 | find "$OPT_DIR" \( -not -iwholename '*.svn/text-base*' -and \( -iname '*.h' -o -iname '*.c' -o -iname '*.cpp' -o -iname '*.cc' \) \) -exec grep -Hn $OPT_CASE "$OPT_STR" '{}' \; 34 | 35 | else 36 | if [[ $# -eq 3 && ! -d $2 ]]; then 37 | echo "$2 is not a valid directory" 38 | elif [[ $# -eq 2 && ! -d $1 ]]; then 39 | echo "$1 is not a valid directory" 40 | fi 41 | 42 | echo "usage: c_srcsearch [-i] [directory] string-to-search" 43 | echo " -i: optional parameter to activate case insensitive search" 44 | echo " directory: optional parameter. c_srcsearch will look for " 45 | echo " string-to-search in this directory" 46 | fi 47 | } 48 | 49 | alias srcsearch=c_srcsearch 50 | -------------------------------------------------------------------------------- /scripts/bash/.vimrc: -------------------------------------------------------------------------------- 1 | set pastetoggle= 2 | set tabstop=4 3 | set shiftwidth=4 4 | set expandtab 5 | 6 | syntax on 7 | colorscheme desert 8 | 9 | autocmd FileType make set noexpandtab 10 | -------------------------------------------------------------------------------- /scripts/bash/command_hacks.sh: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # # 3 | # this file contains a few command line hacks to do miscellaneous things # 4 | # # 5 | ############################################################################## 6 | 7 | # update last modification date of all files which were last 8 | # modified more than 2 years ago (730 days) 9 | # it-ll get update to 'now' 10 | # 11 | find . -type f -mtime +730 -exec touch '{}' \; 12 | 13 | # print all files which were last modified less than 2 days ago 14 | # 15 | find . -type f -mtime -2 -print 16 | -------------------------------------------------------------------------------- /scripts/dat_parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | usage: %(scriptName)s FILE1 -o OUTPUT_FILE 4 | Takes a file with values from 0 to 255 (separated by new line characters) and converts 5 | them to (-1, 1) 6 | An input file should look something like: 7 | 255 8 | 0 9 | 127 10 | 128 11 | 126 12 | 13 | Output would look like: 14 | 1.0000 15 | -1.0000 16 | -0.0039 17 | 0.0039 18 | -0.0118 19 | 20 | """ 21 | 22 | import sys 23 | import os 24 | 25 | def usage(): 26 | """Prints the usage info text extracted from this script's documentation 27 | 28 | """ 29 | print ((__doc__ % {'scriptName' : sys.argv[0]}).lstrip()) 30 | 31 | if __name__ == '__main__': 32 | 33 | if len(sys.argv) != 3: 34 | print("Bad parameters!!!") 35 | usage() 36 | sys.exit(1) 37 | 38 | if not os.path.isfile(sys.argv[1]): 39 | print("error: file %s can't be opened" % (sys.argv[1])) 40 | sys.exit(2) 41 | 42 | try: 43 | file = open(sys.argv[1], 'r') 44 | except IOError as e: 45 | print ("error: %s could not be opened for reading" % (sys.argv[1])) 46 | sys.exit(3) 47 | 48 | try: 49 | filew = open(sys.argv[2], 'w') 50 | except IOError as e: 51 | print ("error: %s could not be opened for writing" % (sys.argv[2])) 52 | sys.exit(4) 53 | 54 | try: 55 | for line in file: 56 | try: 57 | datastr = line.strip().split(' ', 1)[0] 58 | n = int(datastr) 59 | if (n >= 0 and n <= 255): 60 | filew.write ("%.4f\n" % ((n*2/255)-1)) 61 | else: 62 | print("Bad number %d! Ignoring..." % n) 63 | except ValueError: 64 | print("Could not convert data into integer %s" % datastr) 65 | except Exception as e: 66 | print("Unexpected error:", sys.exc_info()[0]) 67 | print(e) 68 | 69 | except: 70 | print("I/O error hadling %s:" % (sys.argv[1]), sys.exc_info()[0]) 71 | 72 | file.close() 73 | filew.close() 74 | -------------------------------------------------------------------------------- /scripts/dummy_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | Usage: %(scriptName)s IP:PORT 4 | 5 | Receive UDP packets on a IP+PORT location and print the size received. 6 | """ 7 | 8 | # Copyright (C) 2013 Faustino Frechilla (frechilla@gmail.com) 9 | # 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to 12 | # deal in the Software without restriction, including without limitation the 13 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | # sell copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | # 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | # 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | # IN THE SOFTWARE. 27 | 28 | import socket, sys 29 | 30 | UDP_MAX_LENGTH = 65507 31 | 32 | def usage(): 33 | print __doc__ % {'scriptName' : sys.argv[0]} 34 | 35 | if __name__ == "__main__": 36 | 37 | if (len(sys.argv) < 2): 38 | usage() 39 | sys.exit(-1) 40 | 41 | # parse ip:port tuple 42 | try: 43 | (ip, port_str) = sys.argv[1].strip().split(':') 44 | except: 45 | usage() 46 | sys.exit(-2) 47 | 48 | # validate port 49 | try: 50 | port = int(port_str) 51 | except: 52 | usage() 53 | sys.exit(-3) 54 | 55 | # validate IP 56 | try: 57 | socket.inet_aton(ip) 58 | except: 59 | usage() 60 | sys.exit(-4) 61 | 62 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 63 | s.bind((ip, port)) 64 | print "Listening on %s:%d" % (ip, port) 65 | while True: 66 | (msg, (remote_addr, remote_port)) = s.recvfrom(UDP_MAX_LENGTH) 67 | print "Received %d bytes of data from %s:%s" % (len(msg), remote_addr, remote_port) 68 | -------------------------------------------------------------------------------- /scripts/log_merger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | usage: %(scriptName)s [options] FILE1 FILE2 [FILE(S)] -o OUTPUT_FILE 4 | 5 | Merge two (or more) timestamped log files into one. 6 | 7 | A timestamped log should look something like: 8 | [01/Jun/2012 12:29:17.953] INFO info message 9 | [01/Jun/2012 12:29:17.983] WARNING warning message 10 | ... 11 | 12 | There are two parameters that tell this script how to merge log messages: 13 | --regex 14 | tells the script how to extract date and message from each log entry. The 15 | regex must contain two groups, one labeled which matches the date 16 | string, and another group labeled , that parses the log string. See 17 | https://docs.python.org/2/library/re.html#regular-expression-syntax to 18 | learn more about regex expressions and groups 19 | --date-fmt 20 | Format of the date tag of each log entry. The group will be analysed 21 | using the format described by this parameter to generete a datetime 22 | python object using strftime. For more info on date formats see 23 | https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior 24 | """ 25 | 26 | # Copyright (C) 2014 Faustino Frechilla (frechilla@gmail.com) 27 | # 28 | # Permission is hereby granted, free of charge, to any person obtaining a copy 29 | # of this software and associated documentation files (the "Software"), to 30 | # deal in the Software without restriction, including without limitation the 31 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 32 | # sell copies of the Software, and to permit persons to whom the Software is 33 | # furnished to do so, subject to the following conditions: 34 | # 35 | # The above copyright notice and this permission notice shall be included in 36 | # all copies or substantial portions of the Software. 37 | # 38 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 39 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 43 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 44 | # IN THE SOFTWARE. 45 | 46 | import sys, os, time, threading, Queue 47 | import re 48 | import datetime 49 | from optparse import OptionParser 50 | 51 | # consts 52 | # 53 | LOG_REGEX_STR_DEFAULT = r'\[(?P[^\]]+)\] (?P[^\n]+)' 54 | DATE_FORMAT_DEFAULT = "%d/%b/%Y %H:%M:%S.%f" 55 | 56 | def usage(): 57 | """Prints the usage info text extracted from this script's documentation 58 | 59 | """ 60 | print (__doc__ % {'scriptName' : sys.argv[0]}).lstrip() 61 | 62 | def parse_ops(): 63 | """The option parser. 64 | 65 | """ 66 | docstring = __doc__ % {'scriptName' : sys.argv[0]} 67 | usage = docstring.split("\n")[1] 68 | # Take the description from the docstring of this file 69 | desc = ''.join(docstring.split("\n")[3:4]) 70 | parser = OptionParser(usage=usage, version="%prog 0.1", description = desc) 71 | 72 | # general ops 73 | parser.add_option("-v", "--verbose", dest="verbose", action="store_true", 74 | help="give more verbose output. Default is OFF") 75 | parser.add_option("-H", "--doc", dest="doc", action="store_true", 76 | help="print this script documentation. It contains a bit more of help about the --regex and --date-fmt parameters") 77 | parser.add_option("-o", "--output", dest="outputfile", action="store", 78 | type="string", 79 | help="path to the file where the output will be written to. If it exists it will be truncated", 80 | metavar="OUTPUT_FILE") 81 | parser.add_option("-r", "--regex", dest="regexp", action="store", 82 | type="string", default=LOG_REGEX_STR_DEFAULT, 83 | help="regular expression to extract dates and messages. Default is \'%s\'" % (LOG_REGEX_STR_DEFAULT), 84 | metavar="REGEXP") 85 | parser.add_option("-d", "--date-fmt", dest="datefmt", action="store", 86 | type="string", default=DATE_FORMAT_DEFAULT, 87 | help="date format in log files. Used to extract the date from the regular expression of option \"--regex\". Default is \'%s\'" % (DATE_FORMAT_DEFAULT), 88 | metavar="REGEXP") 89 | 90 | (parsed_ops, parsed_args) = parser.parse_args() 91 | return (parsed_ops.doc, parsed_ops.verbose, parsed_ops.outputfile, parsed_ops.regexp, parsed_ops.datefmt, parsed_args) 92 | 93 | def read_next_msg(file_handler, regex_obj, date_format): 94 | """Returns the next tuple (date, msg) 95 | (None, None) if the end of the file was hit without any more message tuple 96 | """ 97 | while (True): 98 | line = file_handler.readline() 99 | if (line == ""): 100 | return (None, None) # end of file 101 | else: 102 | m = regex_obj.match(line.rstrip()) 103 | if (m and m.group('date') and m.group('msg')): 104 | date_obj = datetime.datetime.strptime(m.group('date'), date_format) 105 | msg = m.group('msg') 106 | return (date_obj, msg) 107 | 108 | # How did you get to here? 109 | assert (False) 110 | return (None, None) 111 | 112 | 113 | if __name__ == '__main__': 114 | 115 | # Parsing the arguments 116 | # 117 | (my_doc, my_verbose, my_output_file, my_regex, my_datefmt, my_paths) = parse_ops() 118 | if my_verbose: 119 | print "verbose: command line options parsed" 120 | 121 | if (my_doc): 122 | usage() 123 | sys.exit(0) 124 | 125 | # At least 2 log files 126 | # 127 | if len(my_paths) < 2: 128 | print "error: missing parameters" 129 | usage() 130 | sys.exit(1) 131 | 132 | # The output file name must be set 133 | # 134 | if (my_output_file is None): 135 | print "error: output file name missing" 136 | usage() 137 | sys.exit(2) 138 | 139 | # Process regular expression 140 | # 141 | regex_obj = None 142 | try: 143 | regex_obj = re.compile(my_regex) 144 | except Exception as e: 145 | print "error: regular expression \"%s\" can't be processed (%s)" % (my_regex, str(e)) 146 | sys.exit(3) 147 | 148 | # open files to read 149 | # 150 | file_list = [] 151 | for i, file in enumerate(my_paths): 152 | if not os.path.isfile(file): 153 | print "error: file %s (#%d) is not a file" % (file, i) 154 | usage() 155 | sys.exit(4) 156 | else: 157 | try: 158 | file_desc = open(file, 'r') 159 | except IOError as e: 160 | print "error: %s could not be opened (%s)" % (file, str(e)) 161 | sys.exit(5) 162 | file_list.append(file_desc) 163 | if my_verbose: 164 | print "verbose: file %s (#%d) opened" % (file, i) 165 | 166 | # open output file 167 | # 168 | try: 169 | output_handler = open(my_output_file, 'w') 170 | except IOError as e: 171 | print "error: %s could not be opened for writing (%s)" % (my_output_file, str(e)) 172 | sys.exit(6) 173 | except Exception as e: 174 | print "error: unknown exception opening %s for writing (%s)" % (my_output_file, str(e)) 175 | sys.exit(7) 176 | 177 | # working loop 178 | # 179 | try: 180 | if my_verbose: 181 | print "verbose: regular expression set to '%s'" % my_regex 182 | print "verbose: date format '%s'" % my_datefmt 183 | print "verbose: output will be stored at %s" % my_output_file 184 | 185 | dates_list = [] 186 | msg_list = [] 187 | for i, file_handler in enumerate(file_list): 188 | (date_obj, msg_str) = \ 189 | read_next_msg(file_handler, regex_obj, my_datefmt) 190 | if (not date_obj is None): 191 | dates_list.append(date_obj) 192 | msg_list.append(msg_str) 193 | 194 | while (len(dates_list) > 0): 195 | min_index = dates_list.index(min(dates_list)) 196 | output_handler.write("%s - %s\n" % \ 197 | (dates_list[min_index].strftime(my_datefmt), msg_list[min_index])) 198 | 199 | (dates_list[min_index], msg_list[min_index]) = \ 200 | read_next_msg(file_list[min_index], regex_obj, my_datefmt) 201 | if (dates_list[min_index] is None): 202 | if (my_verbose): 203 | print "verbose: end of file %s (index #%d) reached" % \ 204 | (file_list[min_index].name, min_index) 205 | file_list[min_index].close() 206 | del file_list[min_index] 207 | del dates_list[min_index] 208 | del msg_list[min_index] 209 | 210 | except (KeyboardInterrupt, SystemExit) as e: 211 | raise 212 | except Exception as e: 213 | print("error: unexpected exception processing log files (%s)" % str(e)) 214 | raise 215 | 216 | output_handler.close() 217 | -------------------------------------------------------------------------------- /scripts/ntp_mock.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | Usage: %(scriptName)s IP:PORT 4 | Simulate an NTP server on IP and PORT. Sends NTP responses to NTP queries 5 | """ 6 | 7 | import socket 8 | import sys 9 | import ctypes 10 | import struct 11 | import datetime 12 | import math 13 | import time 14 | 15 | # system epoch (1970 in unix) 16 | _SYSTEM_EPOCH = datetime.date(*time.gmtime(0)[0:3]) 17 | # NTP epoch starts off 1900 18 | _NTP_EPOCH = datetime.date(1900, 1, 1) 19 | # delta to convert system epoch to NTP epoch 20 | NTP_DELTA = (_SYSTEM_EPOCH - _NTP_EPOCH).days * 24 * 3600 21 | 22 | def usage(): 23 | print __doc__ % {'scriptName' : sys.argv[0]} 24 | 25 | if __name__ == "__main__": 26 | 27 | if (len(sys.argv) < 2): 28 | usage() 29 | sys.exit(-1) 30 | 31 | # parse ip:port tuple 32 | try: 33 | (ip, port_str) = sys.argv[1].strip().split(':') 34 | except: 35 | usage() 36 | sys.exit(-2) 37 | 38 | # validate port 39 | try: 40 | port = int(port_str) 41 | except: 42 | usage() 43 | sys.exit(-3) 44 | 45 | # Create a UDP socket and bind the socket to the port 46 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 47 | server_address = (ip, port) 48 | print('starting up on {} port {}'.format(*server_address)) 49 | sock.bind(server_address) 50 | 51 | counter = 0 52 | while True: 53 | print('\nwaiting to receive message') 54 | data, address = sock.recvfrom(4096) 55 | 56 | print('received {} bytes from {}'.format( 57 | len(data), address)) 58 | 59 | if data: 60 | # get NTP parameters from the client message 61 | (flags, stratum, interval, precision, root_delay, root_dispersion, ref_id, ref_t, orig_t, rcv_t, xmit_t) = struct.unpack('>BBBBIIIQQQQ', data) 62 | #print (flags, stratum,interval,precision,root_delay,root_dispersion,ref_id,ref_t, orig_t, rcv_t, xmit_t) 63 | 64 | # calculate NTP timestamp based on the system time 65 | secs = (datetime.datetime.utcnow() - datetime.datetime(1970,1,1)).total_seconds() + NTP_DELTA 66 | 67 | # separate integer and floating part for correctly formatting NTP response 68 | (float_part, ntp_secs) = math.modf(secs) 69 | 70 | # floating part is coded in units of 1/(2^32) 71 | ntp_float = 4294967296 * float_part 72 | 73 | # fill in NTP header as server, stratum 1. 74 | # Reference ID is 'GPGL' 75 | # Reference timestamp is set to the integer part of the system timestamp 76 | # Origin timestamp is set to the original timestamp sent by the client 77 | data_to_send = struct.pack('>BBBBIIIIIQIIII', 0x24, 1, 3, 0xe9, 0, 0, 0x4750474c, ntp_secs, 0, xmit_t, ntp_secs, ntp_float, ntp_secs, ntp_float) 78 | 79 | ############################################################################################################# 80 | ######## This hack extracts an NTP payload from a binary file, and generates a response based on the ######## 81 | ######## timestamp stored in thefile and the original xmit timestamp sent by the client ######## 82 | #ntpdumpfile = 'ntp_aurizon_' + str(counter).zfill(2) + '.bin' 83 | #with open(ntpdumpfile, "rb") as f: 84 | # print ntpdumpfile 85 | # data = f.read() 86 | # counter = counter + 1 87 | # (flags, stratum,interval,precision,root_delay,root_dispersion,ref_id,ref_t, NOTIMPORTANT, rcv_t, xmit_cap) = struct.unpack('>BBBBIIIQQQQ', data) 88 | # data_to_send = struct.pack('>BBBBIIIQQQQ', flags, stratum, interval, precision, root_delay, root_dispersion, ref_id, ref_t, xmit_t, rcv_t, xmit_cap) 89 | ############################################################################################################## 90 | 91 | # reply back! 92 | sent = sock.sendto(data_to_send, address) 93 | print('sent {} bytes back to {}'.format(sent, address)) 94 | -------------------------------------------------------------------------------- /scripts/poormansprofiler.sh: -------------------------------------------------------------------------------- 1 | # The poor man's profiler... 2 | # all credit goes to poormansprofiler.org 3 | # 4 | 5 | #!/bin/bash 6 | 7 | function usage 8 | { 9 | echo "$0 APPLICATION [SAMPLES_COUNT] [SLEEPTIME]" 10 | } 11 | 12 | if [[ $# -lt 1 ]]; then 13 | # application name is compulsory... 14 | usage 15 | exit 1 16 | fi 17 | 18 | if [[ $# -gt 1 ]]; then 19 | nsamples=$2 20 | else 21 | nsamples=1 22 | fi 23 | if [[ $# -gt 2 ]]; then 24 | sleeptime=$3 25 | else 26 | sleeptime=0 27 | fi 28 | 29 | pid=`pidof $1` 30 | if [[ $? -ne 0 ]]; then 31 | echo "application $1 is not running" 32 | exit 2 33 | fi 34 | 35 | echo "profiling pid $pid ($1) $nsamples time(s) (sleeptime: $sleeptime)..." 36 | 37 | for x in `seq 1 $nsamples` 38 | do 39 | gdb -ex "set pagination 0" -ex "thread apply all bt" -batch -p $pid 40 | # for gdb 6.3 and older... 41 | # 42 | # (echo "set pagination 0"; 43 | # echo "thread apply all bt; 44 | # echo "quit"; cat /dev/zero ) | gdb -p $(pid) 45 | sleep $sleeptime 46 | done | \ 47 | awk ' 48 | BEGIN { s = ""; } 49 | /^Thread/ {print s; s = ""; } 50 | /^\#/ { if (s != "" ) { s = s "," $4} else { s = $4 } } 51 | END { print s }' | \ 52 | sort | uniq -c | sort -r -n -k 1,1 53 | 54 | -------------------------------------------------------------------------------- /scripts/random_udp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | Usage: %(scriptName)s [options] IP:PORT 4 | 5 | Send UDP packets random in content and size to an IP+PORT location. 6 | Compatible with Python >= 2.6 7 | 8 | """ 9 | 10 | # Copyright (C) 2013 Faustino Frechilla (frechilla@gmail.com) 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 23 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 28 | # IN THE SOFTWARE. 29 | 30 | import struct 31 | import socket 32 | import sys 33 | import random 34 | import array 35 | import time 36 | from optparse import OptionParser, OptionGroup 37 | 38 | ############################################################################## 39 | # Some constants that could be turned into parameters 40 | # 41 | # For the moment the SRC address is set by the kernel. Can't make it work 42 | DEFAULT_SRC_IP = '0.0.0.0' # SRC_IP won't be used (set to the sender's IP) 43 | DEFAULT_SRC_PORT = 0 # If it is 0 it'll be set to DST_PORT when using raw sockets 44 | 45 | IP_HEADER_SIZE = 20 46 | UDP_HEADER_SIZE = 8 47 | DEFAULT_MAX_SIZE = 65535 48 | DEFAULT_MTU = 1500 49 | # print a status msg every DEFAULT_PRINT_OUT_PERIOD messages have been sent 50 | DEFAULT_PRINT_OUT_PERIOD = 1 51 | DEFAULT_USECS_INTERVAL = 0 # default to no wait between messages 52 | USEC_IN_A_SEC = 1000000.0 53 | 54 | 55 | 56 | ############################################################################## 57 | # Functions 58 | # 59 | 60 | def build_ip_header(src_ip, dst_ip): 61 | """Builds a valid IP header and returns it 62 | 63 | Parameters: 64 | - src_ip: A string with a valid IP address which will be used as 65 | SRC IP 66 | - dst_ip: A string with a valid IP address where the packets will be 67 | sent to 68 | 69 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 70 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 71 | |Version| IHL |Type of Service| Total Length | 72 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 73 | | Identification |Flags| Fragment Offset | 74 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 75 | | Time to Live | Protocol | Header Checksum | 76 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 77 | | Source Address | 78 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 79 | | Destination Address | 80 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 81 | | Options | Padding | 82 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 83 | """ 84 | 85 | ihl = 5 86 | version = 4 87 | ip_ihl_ver = (version << 4) | ihl 88 | ip_tos = 0 89 | ip_tot_len = 0 # kernel will fill the correct total length 90 | ip_id = 0xbeef # Id of this packet 91 | ip_frag_off = 0 92 | ip_ttl = 255 93 | ip_proto = socket.IPPROTO_UDP 94 | ip_check = 0 # kernel will fill the correct checksum 95 | ip_saddr = socket.inet_aton (src_ip) # Spoof the src IP if you want to 96 | ip_daddr = socket.inet_aton (dst_ip) 97 | 98 | # the ! in the pack format string means network order 99 | # see http://docs.python.org/2/library/struct.html#format-characters 100 | ip_header = struct.pack('!BBHHHBBH4s4s' , 101 | ip_ihl_ver, ip_tos, ip_tot_len, ip_id, ip_frag_off, ip_ttl, ip_proto, 102 | ip_check, ip_saddr, ip_daddr) 103 | return ip_header 104 | 105 | 106 | def build_udp_header(src_port, dst_port, length): 107 | """Builds a valid UDP header and returns it 108 | 109 | Parameters: 110 | - src_port: A uint16 which will be used as source port for the UDP 111 | header 112 | - dst_port: A uint16 which will be used as destination port for the 113 | UDP header 114 | - length: Length of the data that will be sent in the UDP package. 115 | The actual length field in the UDP package will be 8 bytes 116 | longer to make room for the UDP header itself 117 | 118 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 119 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 120 | | Source port | Destination port | 121 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 122 | | Length | Checksum | 123 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 124 | """ 125 | 126 | if (src_port == DEFAULT_SRC_PORT): 127 | src_port = dst_port 128 | 129 | # error-checking of header AND data. If no checksum is generated set the 130 | # value all-zeros 131 | checksum = 0 132 | udp_header = struct.pack('!HHHH', 133 | src_port, dst_port, (length + 8), checksum); 134 | 135 | return udp_header 136 | 137 | 138 | def parse_ops(): 139 | """The option parser. 140 | 141 | A looooong ugly function, you've been warned 142 | 143 | """ 144 | 145 | docstring = __doc__ % {'scriptName' : sys.argv[0]} 146 | usage = docstring.split("\n")[1] 147 | # Take the description from the docstring of this file 148 | desc = ''.join(docstring.split("\n")[2:]) 149 | parser = OptionParser(usage=usage, version="%prog 0.2", description = desc) 150 | 151 | # general ops 152 | parser.add_option("-u", "--usec-interval", dest="usec", action="store", 153 | type="int", default="0", 154 | help="microseconds between packets sent. Default is 0", 155 | metavar="USEC") 156 | parser.add_option("-v", "--verbose", dest="verbose", action="store_true", 157 | help="give more verbose output. Default is OFF") 158 | 159 | # plain socket ops 160 | group = OptionGroup(parser, "Plain socket options", 161 | "Options available when working with plain sockets (without the \"--raw\" option).") 162 | group.add_option("-m", "--max", dest="max", action="store", type="int", default=DEFAULT_MAX_SIZE, 163 | help="maximum size of every UDP packet sent (default set to 65535). If it is bigger than the MTU of your network IP fragmentation may happen", 164 | metavar="MAX_SIZE") 165 | parser.add_option_group(group) 166 | 167 | # RAW socket ops 168 | group = OptionGroup(parser, "RAW socket options", 169 | "Options available to work with RAW sockets.") 170 | group.add_option("-r", "--raw", dest="raw", action="store_true", 171 | help="Activate RAW sockets (instead of plain sockets). Default is OFF") 172 | group.add_option("-t", "--mtu", dest="mtu", action="store", type="int", default=DEFAULT_MTU, 173 | help="MTU of your network (default set to 1500). This value will be used as the maximum size of the packets when working with RAW sockets", 174 | metavar="MTU") 175 | group.add_option("-p", "--src-port", dest="srcport", action="store", type="int", 176 | help="use SRCPORT as the source port in the UDP packets. Default is set to the destination PORT", 177 | metavar="SRCPORT") 178 | parser.add_option_group(group) 179 | 180 | (parsed_ops, parsed_args) = parser.parse_args() 181 | 182 | # IP:PORT is a mandatory argument 183 | # 184 | if (len(parsed_args) == 0) or (len(parsed_args) > 1): 185 | print "IP:PORT is a mandatory argument" 186 | print usage 187 | sys.exit() 188 | 189 | # checking for a valid destination (IP:PORT) 190 | # 191 | my_dst_port = "" 192 | my_dst_ip = "" 193 | try: 194 | (my_dst_ip, my_dst_port) = parsed_args[0].split(':', 2) 195 | except: 196 | print "Invalid IP:PORT pair" 197 | print usage 198 | sys.exit() 199 | 200 | try: 201 | my_dst_port = int(my_dst_port) 202 | except: 203 | print "Invalid PORT in IP:PORT pair" 204 | print usage 205 | sys.exit() 206 | 207 | if ((my_dst_port <= 0) or (my_dst_port > 0xffff)): 208 | print "PORT must be a valid uint16 number (bigger than 0)" 209 | print usage 210 | sys.exit() 211 | 212 | if ((len(my_dst_ip) < 8) or (len(my_dst_ip) > 15)): 213 | print "IP isn't valid" 214 | print usage 215 | sys.exit() 216 | else: 217 | try: 218 | socket.inet_aton(my_dst_ip) 219 | # legal IP 220 | except socket.error: 221 | print "IP isn't valid" 222 | print usage 223 | sys.exit() 224 | 225 | # checking for a valid microsencs interval 226 | my_usec = DEFAULT_USECS_INTERVAL 227 | if (parsed_ops.usec): 228 | try: 229 | my_usec = int(parsed_ops.usec) 230 | except: 231 | print "Invalid microseconds interval" 232 | print usage 233 | sys.exit() 234 | 235 | # Checking plain socket options 236 | # 237 | my_max = DEFAULT_MAX_SIZE 238 | if (parsed_ops.max): 239 | try: 240 | my_max = int(parsed_ops.max) 241 | except: 242 | print "Invalid Maximum size" 243 | print usage 244 | sys.exit() 245 | 246 | if ((my_max <= 0) or (my_max > 0xffff)): 247 | print "Maximum size for plain sockets must be a valid uint16 number (bigger than 0)" 248 | print usage 249 | sys.exit() 250 | 251 | # time now for RAW socket options 252 | # 253 | my_mtu = DEFAULT_MTU 254 | my_src_port = DEFAULT_SRC_PORT 255 | if (parsed_ops.raw): 256 | # checking for a valid MTU 257 | if (parsed_ops.mtu): 258 | try: 259 | my_mtu = int(parsed_ops.mtu) 260 | except: 261 | print "Invalid MTU" 262 | print usage 263 | sys.exit() 264 | 265 | if ((my_mtu <= 0) or (my_mtu > 0xffff)): 266 | print "MTU must be a valid uint16 number (bigger than 0)" 267 | print usage 268 | sys.exit() 269 | 270 | # checking for a valid source port 271 | # if it is not present it will be set to DEFAULT_SRC_PORT 272 | if (parsed_ops.srcport): 273 | try: 274 | my_src_port = int(parsed_ops.srcport) 275 | except: 276 | print "Invalid SRCPORT number" 277 | print usage 278 | sys.exit() 279 | 280 | if ((my_src_port <= 0) or (my_src_port > 0xffff)): 281 | print "SRCPORT must be a valid uint16 number (bigger than 0)" 282 | print usage 283 | sys.exit() 284 | 285 | return (my_dst_port, my_dst_ip, parsed_ops.verbose, my_usec, my_max, parsed_ops.raw, my_src_port, my_mtu) 286 | 287 | 288 | 289 | ############################################################################## 290 | # MAIN 291 | # 292 | 293 | # Parsing the arguments 294 | # 295 | (my_dst_port, my_dst_ip, my_verbose, my_interval, 296 | my_plain_max, my_use_raw_socket, my_src_port, my_mtu) = parse_ops() 297 | 298 | # transform my_interval from usecs into secs 299 | my_interval /= USEC_IN_A_SEC 300 | 301 | # create the socket that will be used to send the random data 302 | # 303 | if my_use_raw_socket: 304 | if my_verbose: 305 | print "Creating RAW socket. MTU set to %d" % (my_mtu) 306 | if (my_plain_max != DEFAULT_MAX_SIZE): 307 | print "max size of packets is set with \"--max\". Did you mean to use \"--mtu\"?" 308 | try: 309 | # http://www.binarytides.com/raw-socket-programming-in-python-linux/ 310 | # 311 | s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) 312 | #s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, int(1)) 313 | except socket.error, msg: 314 | print 'Raw socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1] 315 | print 'Are you running as root?' 316 | sys.exit() 317 | else: 318 | if my_verbose: 319 | print "Creating plain socket. Maximum length of random packets set to %d" % (my_plain_max) 320 | try: 321 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 322 | except socket.error, msg: 323 | print 'Plain socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1] 324 | sys.exit() 325 | try: 326 | s.bind(('', 0)) 327 | except socket.error, msg: 328 | print 'Plain socket could not bind. Error Code : ' + str(msg[0]) + ' Message ' + msg[1] 329 | sys.exit() 330 | 331 | 332 | # random generator initilisation 333 | # 334 | rangen = None 335 | try: 336 | rangen = random.SystemRandom() 337 | except NotImplementedError, msg: 338 | print 'Warning: random.SystemRandom is not implemented in this OS' 339 | rangen = random 340 | finally: 341 | # Initialize the basic random number generator with current system time 342 | # no matter which random generator we are using 343 | rangen.seed() 344 | 345 | if my_use_raw_socket: 346 | # the IP header. It will be constant throught the execution of the script 347 | # 348 | ip_header = build_ip_header(DEFAULT_SRC_IP, my_dst_ip) 349 | 350 | latest_time = 0 351 | current_time = 0 352 | packet_num = 0 353 | while True: 354 | # length of this packet. 355 | # 356 | if my_use_raw_socket: 357 | length = rangen.randint(1, my_mtu - IP_HEADER_SIZE - UDP_HEADER_SIZE) 358 | else: 359 | length = rangen.randint(1, my_plain_max - IP_HEADER_SIZE - UDP_HEADER_SIZE) 360 | 361 | # can only be used in python >= 2.6 362 | #message = bytearray(rangen.getrandbits(8) for i in xrange(length)) # python >= 2.6 363 | # cant use it because arrays and packed strings cant be concatenated together 364 | #message = array.array('B', (rangen.getrandbits(8) for i in xrange(length))) 365 | 366 | # a random stream of bytes of size 'length' 367 | # 368 | message = struct.pack('B' * length, *(rangen.getrandbits(8) for i in xrange(length))) 369 | 370 | packet_num += 1 371 | if (my_verbose and (packet_num % DEFAULT_PRINT_OUT_PERIOD == 0)): 372 | print "%d: Sending %d bytes of data to %s:%d..." % (packet_num, length, my_dst_ip, my_dst_port) 373 | 374 | current_time = time.time() 375 | if ((latest_time != 0) and (latest_time + my_interval) > current_time): 376 | time.sleep((latest_time + my_interval) - current_time) 377 | 378 | try: 379 | if my_use_raw_socket: 380 | # Send the UDP packet using a raw socket. Concatenate IP_HDR + UDP_HDR + DATA 381 | # 382 | udp_header = build_udp_header(my_src_port, my_dst_port, length) 383 | s.sendto(ip_header + udp_header + message, (my_dst_ip, 0)) 384 | else: 385 | # Send the UDP packet using a plain UDP socket 386 | s.sendto(message, (my_dst_ip, my_dst_port)) 387 | 388 | except socket.error, msg: 389 | print '%d: SendTo failed on a message %d bytes long to %s:%d' % (packet_num, length, my_dst_ip, my_dst_port) 390 | print ' Error Code : ' + str(msg[0]) + '. Message: ' + msg[1] 391 | #sys.exit() 392 | 393 | latest_time = time.time() 394 | 395 | -------------------------------------------------------------------------------- /scripts/rename_pictures.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # This script gets all the files in a directory (passed as parameter) 4 | # and rename them to 'default name' adding at the beginning a number(index), 5 | # which by default starts as 001. it can also be specified as a parameter 6 | # 7 | 8 | use strict; # Declare strict checking on variable names, etc. 9 | use File::Copy; 10 | 11 | my $argc = $#ARGV + 1; 12 | if (($argc != 2) && ($argc != 3)) 13 | { 14 | usage(); 15 | exit(); 16 | } 17 | 18 | # working directory 19 | my $dir = $ARGV[0]; 20 | die("Specified Path '".$dir."' doesn't exist") if !(-d $dir); 21 | 22 | my $defaultName = $ARGV[1]; 23 | 24 | # Index. It will be added at the start of the file 25 | my $index = 1; 26 | if ($argc == 3) 27 | { 28 | $index = $ARGV[2]; 29 | } 30 | 31 | 32 | my @listOfFiles = `ls -tr '$dir'`; 33 | 34 | my $thisFile; 35 | foreach $thisFile (@listOfFiles) 36 | { 37 | # $thisFile contains a \n. Chomp removes it 38 | chomp($thisFile); 39 | 40 | # $dir/$thisFile might be a directory. We only want to rename files 41 | if (-f $dir."/".$thisFile) 42 | { 43 | # some regex magic. retrieve the extension of the file (extension is whatever there is 44 | # after the last '.' (extension in .tar.gz files will be ".tar.gz) 45 | my $extension; 46 | if ($thisFile =~ m/((\.tar)?\.[a-z]+)$/i) 47 | { 48 | $extension = $1; 49 | } 50 | else 51 | { 52 | die("not extension found in file '$dir"."/"."$thisFile'"); 53 | } 54 | 55 | my $indexString = "$index"; 56 | if ($index < 100) 57 | { 58 | $indexString = "0".$indexString; 59 | } 60 | if ($index < 10) 61 | { 62 | $indexString = "0".$indexString; 63 | } 64 | 65 | my $destFile = $dir."/".$indexString."-".$defaultName.$extension; 66 | 67 | print "renaming: ".$dir."/".$thisFile." --> ".$destFile."\n"; 68 | 69 | # don't let the script rename the old file overwriting an existing file 70 | die ("destination file '".$destFile ."' exists. It won't be overwritten") if (-f $destFile); 71 | 72 | # WARNING 73 | # Uncomment these lines if you want the script to do what is meant to do 74 | # free advice: Run it first with this line commented out and have a look to the output 75 | # if you are happy with the output run it again with this line uncommented 76 | if (!move($dir."/".$thisFile, $destFile)) 77 | { 78 | die ("shit! Error renaming that latest file"); 79 | } 80 | $index++; 81 | } 82 | } 83 | 84 | 85 | ########################################################### 86 | # Print the usage options of the script 87 | sub usage() 88 | { 89 | # $^X: The name that Perl itself was executed as, from argv[0] 90 | print "Usage: perl " . $^X . " directory 'default name' [start index]\n"; 91 | print qq[ 92 | This script gets all the files in a directory (passed as parameter) 93 | and rename them to 'default name' adding at the beginning a number(index), 94 | which by default starts as 001. it can also be specified as a parameter 95 | 96 | ]; 97 | } 98 | 99 | --------------------------------------------------------------------------------