text: /*
   *  RPLIDAR SDK
   *
   *  Copyright (c) 2009 - 2014 RoboPeak Team
   *  http://www.robopeak.com
   *  Copyright (c) 2014 - 2020 Shanghai Slamtec Co., Ltd.
   *  http://www.slamtec.com
   *
   */
  /*
   * Redistribution and use in source and binary forms, with or without 
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice, 
   *    this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright notice, 
   *    this list of conditions and the following disclaimer in the documentation 
   *    and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
   * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   */
  
  #pragma once
  namespace rp{ namespace hal{
  
  class Event
  {
  public:
      
      enum
      {
          EVENT_OK = 1,
          EVENT_TIMEOUT = -1,
          EVENT_FAILED = 0,
      };
      
      Event(bool isAutoReset = true, bool isSignal = false)
  #ifdef _WIN32
          : _event(NULL)
  #else
          : _is_signalled(isSignal)
          , _isAutoReset(isAutoReset)
  #endif
      {
  #ifdef _WIN32
          _event = CreateEvent(NULL, isAutoReset?FALSE:TRUE, isSignal?TRUE:FALSE, NULL); 
  #else
          pthread_mutex_init(&_cond_locker, NULL);
          pthread_cond_init(&_cond_var, NULL);
  #endif
      }
  
      ~ Event()
      {
          release();
      }
  
      void set( bool isSignal = true )
      {
          if (isSignal){
  #ifdef _WIN32
              SetEvent(_event);
  #else
              pthread_mutex_lock(&_cond_locker);
                 
              if ( _is_signalled == false )
              {
                  _is_signalled = true;
                  pthread_cond_signal(&_cond_var);
              }
              pthread_mutex_unlock(&_cond_locker);
  #endif
          }
          else
          {
  #ifdef _WIN32
              ResetEvent(_event);
  #else
              pthread_mutex_lock(&_cond_locker);
              _is_signalled = false;
              pthread_mutex_unlock(&_cond_locker);
  #endif
          }
      }
      
      signed long wait( unsigned long timeout = 0xFFFFFFFF )
      {
  #ifdef _WIN32
          switch (WaitForSingleObject(_event, timeout==0xFFFFFFF?INFINITE:(DWORD)timeout))
          {
          case WAIT_FAILED:
              return EVENT_FAILED;
          case WAIT_OBJECT_0:
              return EVENT_OK;
          case WAIT_TIMEOUT:
              return EVENT_TIMEOUT;
          }
          return EVENT_OK;
  #else
          signed long ans = EVENT_OK;
          pthread_mutex_lock( &_cond_locker );
  
          if ( !_is_signalled )
          {
              
                  if (timeout == 0xFFFFFFFF){
                      pthread_cond_wait(&_cond_var,&_cond_locker);
                  }else
                  {
                      timespec wait_time;
                      timeval now;
                      gettimeofday(&now,NULL);
  
                      wait_time.tv_sec = timeout/1000 + now.tv_sec;
                      wait_time.tv_nsec = (timeout%1000)*1000000ULL + now.tv_usec*1000;
                  
                      if (wait_time.tv_nsec >= 1000000000)
                      {
                         ++wait_time.tv_sec;
                         wait_time.tv_nsec -= 1000000000;
                      }
                      switch (pthread_cond_timedwait(&_cond_var,&_cond_locker,&wait_time))
                      {
                      case 0:
                          // signalled
                          break;
                      case ETIMEDOUT:
                          // time up
                          ans = EVENT_TIMEOUT;
                          goto _final;
                          break;
                      default:
                          ans = EVENT_FAILED;
                          goto _final;
                      }
         
              }
          }
            
          assert(_is_signalled);
  
          if ( _isAutoReset )
          {
              _is_signalled = false;
          }
  _final:
          pthread_mutex_unlock( &_cond_locker );
  
          return ans;
  #endif
          
      }
  protected:
  
      void release()
      {
  #ifdef _WIN32
          CloseHandle(_event);
  #else
          pthread_mutex_destroy(&_cond_locker);
          pthread_cond_destroy(&_cond_var);
  #endif
      }
  
  #ifdef _WIN32
          HANDLE _event;
  #else
          pthread_cond_t         _cond_var;
          pthread_mutex_t        _cond_locker;
          bool                   _is_signalled;
          bool                   _isAutoReset;
  #endif
  };
  }}
  