
// SPDX-License-Identifier: CC-BY-NC-SA-4.0
//
// Copyright (C) 2026 Bit by Bit Signal Processing LLC (https://bxbsp.com)
//
// This work is placed under the "Creative Commons Attribution
// NonCommercial ShareAlike 4.0 International" license, known
// by the shortened acronym "CC-BY-NC-SA-4.0".
//
// This work is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// A CC-BY-NC-SA-4.0 license allows you to use this work for
// noncommercial purposes so long as attribution is made to the
// original author.  Modified versions of this work may be distributed,
// but only under the same license.  For further details, see the
// Creative Commons License "CC-BY-NC-SA-4.0".
//
// You should have received a copy of the CC-BY-NC-SA-4.0 license
// along with this work. If not, see
// <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
//
//

#ifndef RUNNABLE_HH
#define RUNNABLE_HH

#include <pthread.h>

#include <stdio.h>
#include <stdlib.h>

//
// To use this class:  Derive some other class from this class, containing
// any thread variables.  Inside the constructor for the derived class, call
// start() to start up the thread.  This will call the virtual run() method
// of the derived class from a newly started thread.
//
// Alternately, you can have a function such as
//    void thread_1_main(void* thread_data);
//
// And then start it with
//    runnable start_thread_1(thread_1_main, thread_data);
//
class runnable
{
private:

  pthread_t       thread_id;
  void            (*thread_main)(void*);
  void*           thread_data;

  static void*    static_run(runnable* r) { r->run(); return 0; }

public:

  virtual void    run()  { if(!thread_main) { printf("Error: need to override run method in runnable.\n"); exit(20); } thread_main(thread_data); }

  pthread_t       get_thread_id() const     { return thread_id; }

//
// Called externally from the thread
//
                  runnable() {   thread_id = 0; thread_main = 0; }
  runnable(void (*thread_main)(void*), void* thread_data) { thread_id = 0; this->thread_data = thread_data; this->thread_main = thread_main; start(); }
  virtual        ~runnable();

  void            start();
  void            cancel()              { pthread_cancel(thread_id);  }
  void            wait_for_completion() { pthread_join(thread_id, 0); }

//
// Called from within the thread
//
  void            wait(int milliseconds);
  void            wait()                    { wait(10); }
};



#endif
