[beast: 24/95] BSE: add TickStamp class, use Bse::TickStamp instead of old gsl API



commit f357e41f30fb6d31026565ae9db33236ce30f454
Author: Tim Janik <timj gnu org>
Date:   Sat Mar 16 19:54:51 2013 +0100

    BSE: add TickStamp class, use Bse::TickStamp instead of old gsl API

 bse/bseengine.cc         |   26 ++++----
 bse/bseenginemaster.cc   |   26 ++++----
 bse/bseenginenode.hh     |    2 +-
 bse/bseengineschedule.cc |    4 +-
 bse/bseengineutils.cc    |    4 +-
 bse/bsepcmdevice-null.cc |    2 +-
 bse/bseprobe.cc          |    4 +-
 bse/bseproject.cc        |    2 +-
 bse/bsesequencer.cc      |   40 ++++++-----
 bse/bsesequencer.hh      |    9 ++-
 bse/bsesong.proc         |    2 +-
 bse/bsewaveosc.cc        |    2 +-
 bse/gslcommon.cc         |  173 ++++++++++++++++++++++++++++++++--------------
 bse/gslcommon.hh         |   57 +++++++++++----
 14 files changed, 231 insertions(+), 122 deletions(-)
---
diff --git a/bse/bseengine.cc b/bse/bseengine.cc
index 10e37c1..0084f52 100644
--- a/bse/bseengine.cc
+++ b/bse/bseengine.cc
@@ -69,9 +69,9 @@ bse_module_new (const BseModuleClass *klass,
  * @return             the module's tick stamp, indicating its process status
  *
  * Any thread may call this function on a valid engine module.
- * The module specific tick stamp is updated to gsl_tick_stamp() +
+ * The module specific tick stamp is updated to Bse::TickStamp::current() +
  * @a n_values every time its BseProcessFunc() function was
- * called. See also gsl_tick_stamp().
+ * called. See also Bse::TickStamp::current().
  * This function is MT-safe and may be called from any thread.
  */
 guint64
@@ -499,7 +499,7 @@ bse_job_flow_access (BseModule    *module,
   BseJob *job;
   g_return_val_if_fail (module != NULL, NULL);
   g_return_val_if_fail (ENGINE_MODULE_IS_VIRTUAL (module) == FALSE, NULL);
-  g_return_val_if_fail (tick_stamp < GSL_MAX_TICK_STAMP, NULL);
+  g_return_val_if_fail (tick_stamp < Bse::TickStamp::max_stamp(), NULL);
   g_return_val_if_fail (access_func != NULL, NULL);
   EngineTimedJob *tjob = (EngineTimedJob*) g_malloc0 (sizeof (tjob->access));
   tjob->type = ENGINE_JOB_FLOW_JOB;
@@ -540,7 +540,7 @@ bse_job_boundary_access (BseModule    *module,
   BseJob *job;
   g_return_val_if_fail (module != NULL, NULL);
   g_return_val_if_fail (ENGINE_MODULE_IS_VIRTUAL (module) == FALSE, NULL);
-  g_return_val_if_fail (tick_stamp < GSL_MAX_TICK_STAMP, NULL);
+  g_return_val_if_fail (tick_stamp < Bse::TickStamp::max_stamp(), NULL);
   g_return_val_if_fail (access_func != NULL, NULL);
   EngineTimedJob *tjob = (EngineTimedJob*) g_malloc0 (sizeof (tjob->access));
   tjob->type = ENGINE_JOB_BOUNDARY_JOB;
@@ -609,7 +609,7 @@ bse_job_suspend_now (BseModule *module)
   BseJob *job = sfi_new_struct0 (BseJob, 1);
   job->job_id = ENGINE_JOB_SUSPEND;
   job->tick.node = ENGINE_NODE (module);
-  job->tick.stamp = GSL_MAX_TICK_STAMP;
+  job->tick.stamp = Bse::TickStamp::max_stamp();
   return job;
 }
 /**
@@ -633,7 +633,7 @@ bse_job_resume_at (BseModule *module,
 {
   g_return_val_if_fail (module != NULL, NULL);
   g_return_val_if_fail (ENGINE_MODULE_IS_VIRTUAL (module) == FALSE, NULL);
-  g_return_val_if_fail (tick_stamp < GSL_MAX_TICK_STAMP, NULL);
+  g_return_val_if_fail (tick_stamp < Bse::TickStamp::max_stamp(), NULL);
   BseJob *job = sfi_new_struct0 (BseJob, 1);
   job->job_id = ENGINE_JOB_RESUME;
   job->tick.node = ENGINE_NODE (module);
@@ -863,7 +863,7 @@ bse_trans_merge (BseTrans *trans1,
  * Close the transaction and commit it to the engine. The engine
  * will execute the jobs contained in this transaction as soon as
  * it has completed its current processing cycle, at which point
- * gsl_tick_stamp() matches the returned tick stamp.
+ * Bse::TickStamp::current() matches the returned tick stamp.
  * The jobs will be executed in the exact order they were added
  * to the transaction.
  * This function is MT-safe and may be called from any thread.
@@ -930,7 +930,7 @@ bse_trans_commit_delayed (BseTrans *trans,
 {
   g_return_if_fail (trans != NULL);
   g_return_if_fail (trans->comitted == FALSE);
-  if (tick_stamp <= gsl_tick_stamp ())
+  if (tick_stamp <= Bse::TickStamp::current())
     bse_trans_commit (trans);
   else
     {
@@ -1110,7 +1110,7 @@ guint                     bse_engine_exvar_control_mask = 0;
  * @a sample_freq. It determines how often control values are to be
  * checked when calculating blocks of sample values.
  * The block size determines the amount by which the global tick
- * stamp (see gsl_tick_stamp()) is updated everytime the whole
+ * stamp (see Bse::TickStamp::current()) is updated everytime the whole
  * module network completed processing block size values.
  * This function is MT-safe and may be called prior to engine initialization.
  */
@@ -1228,8 +1228,8 @@ bse_engine_configure (guint            latency_ms,
       bse_engine_exvar_sample_freq = sample_freq;
       bse_engine_exvar_control_mask = control_raster - 1;
       /* fixup timer */
-      _gsl_tick_stamp_set_leap (bse_engine_block_size());
-      _gsl_tick_stamp_inc ();   /* ensure stamp validity (>0 and systime mark) */
+      Bse::TickStamp::_set_leap (bse_engine_block_size());
+      Bse::TickStamp::_increment(); // ensure stamp validity (>0 and systime mark)
       success = TRUE;
     }
   /* unblock master */
@@ -1380,7 +1380,7 @@ bse_engine_get_threads (guint *n_threads)
 guint64
 bse_engine_tick_stamp_from_systime (guint64 systime)
 {
-  GslTickStampUpdate ustamp = gsl_tick_stamp_last ();
+  Bse::TickStamp::Update ustamp = Bse::TickStamp::get_last ();
   guint64 tick_stamp;
   /* FIXME: we should add special guards here
    * for sfi_time_system() - ustamp.system_time ~> (44100 / bse_engine_block_size ())
@@ -1407,7 +1407,7 @@ bse_engine_tick_stamp_from_systime (guint64 systime)
             "  last-update-systime   = %llu\n"
             "  last-update-tickstamp = %llu\n"
             "  sample-freq           = %u\n",
-            tick_stamp, systime, sfi_time_system (), gsl_tick_stamp (),
+            tick_stamp, systime, sfi_time_system (), Bse::TickStamp::get_current (),
             ustamp.system_time, ustamp.tick_stamp,
             bse_engine_sample_freq ());
 #endif
diff --git a/bse/bseenginemaster.cc b/bse/bseenginemaster.cc
index ccb76f2..c2f4abf 100644
--- a/bse/bseenginemaster.cc
+++ b/bse/bseenginemaster.cc
@@ -238,7 +238,7 @@ node_peek_flow_job_stamp (EngineNode *node)
   EngineTimedJob *tjob = node->flow_jobs;
   if (UNLIKELY (tjob != NULL))
     return tjob->tick_stamp;
-  return GSL_MAX_TICK_STAMP;
+  return Bse::TickStamp::max_stamp();
 }
 static inline guint64
 node_peek_boundary_job_stamp (EngineNode *node)
@@ -246,7 +246,7 @@ node_peek_boundary_job_stamp (EngineNode *node)
   EngineTimedJob *tjob = node->boundary_jobs;
   if (UNLIKELY (tjob != NULL))
     return tjob->tick_stamp;
-  return GSL_MAX_TICK_STAMP;
+  return Bse::TickStamp::max_stamp();
 }
 /* --- job processing --- */
 static void
@@ -281,7 +281,7 @@ master_process_job (BseJob *job)
       _engine_mnl_integrate (node);
       if (ENGINE_NODE_IS_CONSUMER (node))
        add_consumer (node);
-      node->counter = GSL_TICK_STAMP;
+      node->counter = Bse::TickStamp::current();
       NODE_FLAG_RECONNECT (node);
       node->local_active = 0;   /* by default not suspended */
       node->update_suspend = TRUE;
@@ -334,10 +334,10 @@ master_process_job (BseJob *job)
        }
       else
        _engine_mnl_remove (node);
-      node->counter = GSL_MAX_TICK_STAMP;
+      node->counter = Bse::TickStamp::max_stamp();
       /* nuke pending timed jobs */
       do
-        tjob = node_pop_flow_job (node, GSL_MAX_TICK_STAMP);
+        tjob = node_pop_flow_job (node, Bse::TickStamp::max_stamp());
       while (tjob);
       /* nuke probe jobs */
       if (node->probe_jobs)
@@ -353,7 +353,7 @@ master_process_job (BseJob *job)
       /* nuke boundary jobs */
       if (node->boundary_jobs)
         do
-          tjob = node_pop_boundary_job (node, GSL_MAX_TICK_STAMP, sfi_ring_find (boundary_node_list, node));
+          tjob = node_pop_boundary_job (node, Bse::TickStamp::max_stamp(), sfi_ring_find 
(boundary_node_list, node));
         while (tjob);
       _engine_node_collect_jobs (node);
       break;
@@ -483,14 +483,14 @@ master_process_job (BseJob *job)
       node = job->data.node;
       JOB_DEBUG ("reset(%p)", node);
       g_return_if_fail (node->integrated == TRUE);
-      node->counter = GSL_TICK_STAMP;
+      node->counter = Bse::TickStamp::current();
       node->needs_reset = TRUE;
       break;
     case ENGINE_JOB_ACCESS:
       node = job->access.node;
       JOB_DEBUG ("access node(%p): %p(%p)", node, job->access.access_func, job->access.data);
       g_return_if_fail (node->integrated == TRUE);
-      node->counter = GSL_TICK_STAMP;
+      node->counter = Bse::TickStamp::current();
       job->access.access_func (&node->module, job->access.data);
       break;
     case ENGINE_JOB_PROBE_JOB:
@@ -632,8 +632,8 @@ master_tick_stamp_inc (void)
 {
   Timer *timer, *last = NULL;
   guint64 new_stamp;
-  _gsl_tick_stamp_inc ();
-  new_stamp = GSL_TICK_STAMP;
+  Bse::TickStamp::_increment();
+  new_stamp = Bse::TickStamp::current();
   timer = master_timer_list;
   while (timer)
     {
@@ -743,7 +743,7 @@ static void
 master_process_locked_node (EngineNode *node,
                            guint       n_values)
 {
-  const guint64 current_stamp = GSL_TICK_STAMP;
+  const guint64 current_stamp = Bse::TickStamp::current();
   guint64 next_counter, new_counter, final_counter = current_stamp + n_values;
   guint i, j, diff;
   bool needs_probe_reset = node->probe_jobs != NULL;
@@ -820,7 +820,7 @@ static gboolean gsl_profile_modules = 0;    /* set to 1 in gdb to get profile outpu
 static void
 master_process_flow (void)
 {
-  const guint64 current_stamp = GSL_TICK_STAMP;
+  const guint64 current_stamp = Bse::TickStamp::current();
   guint n_values = bse_engine_block_size();
   guint64 final_counter = current_stamp + n_values;
   guint64 profile_maxtime = 0;
@@ -981,7 +981,7 @@ _engine_master_check (const BseEngineLoop *loop)
 void
 _engine_master_dispatch_jobs (void)
 {
-  const guint64 current_stamp = GSL_TICK_STAMP;
+  const guint64 current_stamp = Bse::TickStamp::current();
   guint64 last_block_tick = current_stamp + bse_engine_block_size() - 1;
   BseJob *job = _engine_pop_job (boundary_node_list == NULL);
   /* here, we have to process _all_ pending jobs in a row. a popped job
diff --git a/bse/bseenginenode.hh b/bse/bseenginenode.hh
index dac9e2e..3372bcc 100644
--- a/bse/bseenginenode.hh
+++ b/bse/bseenginenode.hh
@@ -159,7 +159,7 @@ struct _EngineNode          /* fields sorted by order of processing access */
 {
   BseModule     module;
   BirnetRecMutex        rec_mutex;     /* processing lock */
-  guint64       counter;       /* <= GSL_TICK_STAMP */
+  guint64       counter;       /* <= Bse::TickStamp::current() */
   EngineInput  *inputs;        /* [ENGINE_NODE_N_ISTREAMS()] */
   EngineJInput **jinputs;      /* [ENGINE_NODE_N_JSTREAMS()][jstream->jcount] */
   EngineOutput *outputs;       /* [ENGINE_NODE_N_OSTREAMS()] */
diff --git a/bse/bseengineschedule.cc b/bse/bseengineschedule.cc
index 2e53dd0..4d1fc3b 100644
--- a/bse/bseengineschedule.cc
+++ b/bse/bseengineschedule.cc
@@ -363,7 +363,7 @@ determine_suspension_state (EngineNode *node,
     {
       node->in_suspend_call = TRUE;
       SfiRing *ring;    /* calculate outer suspend constraints */
-      stamp = ENGINE_NODE_IS_CONSUMER (node) ? 0 : GSL_MAX_TICK_STAMP;
+      stamp = ENGINE_NODE_IS_CONSUMER (node) ? 0 : Bse::TickStamp::max_stamp();
       gboolean keep_state = FALSE;
       for (ring = node->output_nodes; ring; ring = sfi_ring_walk (ring, node->output_nodes))
         {
@@ -687,7 +687,7 @@ subschedule_query_node (EngineSchedule *schedule,
        guint child_ostream = node->jinputs[j][i].real_stream;
        subschedule_child (schedule, node, query, child, child_ostream);
       }
-  node->counter = GSL_TICK_STAMP;
+  node->counter = Bse::TickStamp::current();
   node->sched_recurse_tag = FALSE;
   /* SCHED_DEBUG ("sched_done(%p)", node); */
 }
diff --git a/bse/bseengineutils.cc b/bse/bseengineutils.cc
index dd84036..ed1662f 100644
--- a/bse/bseengineutils.cc
+++ b/bse/bseengineutils.cc
@@ -278,7 +278,7 @@ _engine_pop_job (gboolean update_commit_stamp)
          cqueue_trans_pending_tail = NULL;
           cqueue_trans_job = cqueue_trans_active_head ? cqueue_trans_active_head->jobs_head : NULL;
           if (!cqueue_trans_job && update_commit_stamp)
-            cqueue_commit_base_stamp = gsl_tick_stamp();        /* last job has been handed out */
+            cqueue_commit_base_stamp = Bse::TickStamp::current();        /* last job has been handed out */
          GSL_SPIN_UNLOCK (&cqueue_trans);
          sfi_cond_broadcast (&cqueue_trans_cond);
        }
@@ -301,7 +301,7 @@ _engine_pop_job (gboolean update_commit_stamp)
          cqueue_trans_pending_tail = NULL;
           cqueue_trans_job = cqueue_trans_active_head ? cqueue_trans_active_head->jobs_head : NULL;
           if (!cqueue_trans_job && update_commit_stamp)
-            cqueue_commit_base_stamp = gsl_tick_stamp();        /* last job has been handed out */
+            cqueue_commit_base_stamp = Bse::TickStamp::current();        /* last job has been handed out */
          GSL_SPIN_UNLOCK (&cqueue_trans);
        }
     }
diff --git a/bse/bsepcmdevice-null.cc b/bse/bsepcmdevice-null.cc
index 7bc5f40..088b41a 100644
--- a/bse/bsepcmdevice-null.cc
+++ b/bse/bsepcmdevice-null.cc
@@ -71,7 +71,7 @@ null_device_check_io (BsePcmHandle *handle,
                       glong        *timeoutp)
 {
   /* keep the sequencer busy or we will constantly timeout */
-  sfi_thread_wakeup (bse_sequencer_thread);
+  bse_sequencer_wakeup();
   *timeoutp = 1;
   /* ensure sequencer fairness */
   return !bse_sequencer_thread_lagging (2);
diff --git a/bse/bseprobe.cc b/bse/bseprobe.cc
index bdcc4af..112d0dc 100644
--- a/bse/bseprobe.cc
+++ b/bse/bseprobe.cc
@@ -2,7 +2,7 @@
 #include "bseprobe.genidl.hh"
 #include "bseengine.hh"
 #include "bseblockutils.hh"
-#include "gslcommon.hh" /* for gsl_tick_stamp() */
+#include "gslcommon.hh" /* for Bse::TickStamp::current() */
 #include "gslfft.hh"
 #include "bsemain.hh"
 #include "bsesequencer.hh"
@@ -687,7 +687,7 @@ source_mass_request::exec (const ProbeRequestSeq &cprseq)
 Num
 source_get_tick_stamp::exec (BseSource *self)
 {
-  return gsl_tick_stamp ();
+  return Bse::TickStamp::current();
 }
 Int
 source_get_mix_freq::exec (BseSource *self)
diff --git a/bse/bseproject.cc b/bse/bseproject.cc
index ba4c04e..ff9a314 100644
--- a/bse/bseproject.cc
+++ b/bse/bseproject.cc
@@ -654,7 +654,7 @@ bse_project_state_changed (BseProject     *self,
   self->state = state;
   if (self->state == BSE_PROJECT_ACTIVE && self->deactivate_usecs >= 0)
     {
-      SfiTime stamp = gsl_tick_stamp ();
+      SfiTime stamp = Bse::TickStamp::current();
       SfiTime delay_usecs = 0;
       if (SfiTime (self->deactivate_min_tick) > stamp)
        delay_usecs = (self->deactivate_min_tick - stamp) * 1000000 / bse_engine_sample_freq ();
diff --git a/bse/bsesequencer.cc b/bse/bsesequencer.cc
index 293da74..e1ca94f 100644
--- a/bse/bsesequencer.cc
+++ b/bse/bsesequencer.cc
@@ -15,15 +15,18 @@
 #include <errno.h>
 #include <string.h>
 #include <vector>
+using namespace std;    // FIXME
+
 /* due to a linker/compiler bug on SuSE 9.2, we need to
  * define extern "C" symbols outside of any C++ namespace,
  * in order for C code to link against it.
  */
 extern "C" { BirnetThread *bse_sequencer_thread = NULL; }
-using namespace std;
+
 #define CHECKTRACE()    UNLIKELY (bse_trace_args.sequencer)
 #define SEQTRACE(...)   do { if (CHECKTRACE()) sfi_debug_channel_printf (bse_trace_args.sequencer, NULL, 
__VA_ARGS__); } while (0)
 #define        BSE_SEQUENCER_FUTURE_BLOCKS    (7)
+
 /* --- prototypes --- */
 static void    bse_sequencer_thread_main       (gpointer        data);
 static void    bse_sequencer_process_song_SL   (BseSong        *song,
@@ -32,6 +35,7 @@ static void   bse_sequencer_process_song_SL   (BseSong        *song,
 static BseSequencer    *global_sequencer = NULL;
 static BirnetCond          current_watch_cond = { 0, };
 static gint             sequencer_wake_up_pipe[2] = { -1, -1 };
+
 /* --- functions --- */
 extern "C" void
 bse_sequencer_init_thread (void)
@@ -46,15 +50,16 @@ bse_sequencer_init_thread (void)
   fcntl (sequencer_wake_up_pipe[1], F_SETFL, O_NONBLOCK | flags);
   /* initialize BseSequencer */
   static BseSequencer sseq = { 0, };
-  sseq.stamp = gsl_tick_stamp ();
+  sseq.stamp = Bse::TickStamp::current();
   g_assert (sseq.stamp > 0);
   global_sequencer = &sseq;
   bse_sequencer_thread = sfi_thread_run ("Sequencer", bse_sequencer_thread_main, NULL);
   if (!bse_sequencer_thread)
     g_error ("failed to create sequencer thread");
 }
-static void
-sequencer_wake_up (gpointer wake_up_data)
+
+void
+bse_sequencer_wakeup ()
 {
   guint8 wake_up_message = 'W';
   gint err;
@@ -62,6 +67,7 @@ sequencer_wake_up (gpointer wake_up_data)
     err = write (sequencer_wake_up_pipe[1], &wake_up_message, 1);
   while (err < 0 && errno == EINTR);
 }
+
 namespace { // Anon
 class PollPool {
 public:
@@ -221,7 +227,7 @@ bse_sequencer_remove_io_watch (BseIOWatch      watch_func,
     {
       removal_success = sequencer_poll_pool.remove_watch (watch_func, watch_data);
       /* wake up sequencer thread, so it stops polling on fds it doesn't own anymore */
-      sfi_thread_wakeup (bse_sequencer_thread);
+      bse_sequencer_wakeup();
     }
   BSE_SEQUENCER_UNLOCK ();
   if (!removal_success)
@@ -297,7 +303,7 @@ bse_sequencer_start_song (BseSong        *song,
     }
   global_sequencer->songs = sfi_ring_append (global_sequencer->songs, song);
   BSE_SEQUENCER_UNLOCK ();
-  sfi_thread_wakeup (bse_sequencer_thread);
+  bse_sequencer_wakeup();
 }
 extern "C" void
 bse_sequencer_remove_song (BseSong *song)
@@ -351,7 +357,7 @@ extern "C" gboolean
 bse_sequencer_thread_lagging (guint n_blocks)
 {
   /* return whether the sequencer lags for n_blocks future stamps */
-  const guint64 cur_stamp = gsl_tick_stamp ();
+  const guint64 cur_stamp = Bse::TickStamp::current();
   guint64 next_stamp = cur_stamp + n_blocks * bse_engine_block_size();
   BSE_SEQUENCER_LOCK ();
   gboolean lagging = global_sequencer->stamp < next_stamp;
@@ -361,13 +367,13 @@ bse_sequencer_thread_lagging (guint n_blocks)
 static void
 bse_sequencer_thread_main (gpointer data)
 {
-  SEQTRACE ("SEQ:thrdstrt: now=%llu", gsl_tick_stamp());
-  sfi_thread_set_wakeup (sequencer_wake_up, NULL, NULL);
+  SEQTRACE ("SEQ:thrdstrt: now=%llu", Bse::TickStamp::current());
+  Bse::TickStampWakeupP wakeup = Bse::TickStamp::create_wakeup (bse_sequencer_wakeup);
   bse_message_setup_thread_handler();
   BSE_SEQUENCER_LOCK ();
   do
     {
-      const guint64 cur_stamp = gsl_tick_stamp ();
+      const guint64 cur_stamp = Bse::TickStamp::current();
       guint64 next_stamp = cur_stamp + BSE_SEQUENCER_FUTURE_BLOCKS * bse_engine_block_size();
       SfiRing *ring;
       for (ring = global_sequencer->songs; ring; ring = sfi_ring_walk (ring, global_sequencer->songs))
@@ -412,11 +418,11 @@ bse_sequencer_thread_main (gpointer data)
            }
        }
       global_sequencer->stamp = next_stamp;
-      sfi_thread_awake_after (cur_stamp + bse_engine_block_size ());
+      wakeup->awake_after (cur_stamp + bse_engine_block_size ());
     }
   while (bse_sequencer_poll_Lm (-1));
   BSE_SEQUENCER_UNLOCK ();
-  SEQTRACE ("SEQ:thrdstop: now=%llu", gsl_tick_stamp());
+  SEQTRACE ("SEQ:thrdstop: now=%llu", Bse::TickStamp::current());
 }
 static void
 bse_sequencer_process_track_SL (BseTrack        *track,
@@ -506,13 +512,13 @@ bse_sequencer_process_track_SL (BseTrack        *track,
   if (!part && next)
     {
       part = bse_track_get_part_SL (track, next, &start, &next);
-      SEQTRACE ("SEQ:trackjmp: tick=%u fast forward to first part part=%p now=%llu", start_tick, part, 
gsl_tick_stamp());
+      SEQTRACE ("SEQ:trackjmp: tick=%u fast forward to first part part=%p now=%llu", start_tick, part, 
Bse::TickStamp::current());
     }
   if (!part || (next == 0 && start + part->last_tick_SL < start_tick))
     {
       track->track_done_SL = !bse_midi_receiver_voices_pending (midi_receiver, track->midi_channel_SL);
       SEQTRACE ("SEQ:trackchk: tick=%u next=%u part=%p done=%u now=%llu", // part==NULL || start + (part ? 
part->last_tick_SL : 0) < start_tick
-                start_tick, next, part, track->track_done_SL, gsl_tick_stamp());
+                start_tick, next, part, track->track_done_SL, Bse::TickStamp::current());
       part = NULL;
     }
   while (part && start < bound)
@@ -563,9 +569,9 @@ bse_sequencer_process_part_SL (BsePart         *part,
           if (CHECKTRACE())
             {
               SEQTRACE ("SEQ:note-on:  tick=%llu midinote=%-3d velocity=%02x freq=% 10f now=%llu",
-                        eon->delta_time,  note->note, bse_ftoi (note->velocity * 128), freq, 
gsl_tick_stamp());
+                        eon->delta_time,  note->note, bse_ftoi (note->velocity * 128), freq, 
Bse::TickStamp::current());
               SEQTRACE ("SEQ:note-off: tick=%llu midinote=%-3d velocity=%02x freq=% 10f now=%llu",
-                        eoff->delta_time, note->note, bse_ftoi (note->velocity * 128), freq, 
gsl_tick_stamp());
+                        eoff->delta_time, note->note, bse_ftoi (note->velocity * 128), freq, 
Bse::TickStamp::current());
             }
           note++;
         }
@@ -582,7 +588,7 @@ bse_sequencer_process_part_SL (BsePart         *part,
                                                        BseMidiSignalType (cev->ctype), cev->value);
           bse_midi_receiver_push_event (midi_receiver, event);
           SEQTRACE ("SEQ:control:  tick=%llu midisignal=%-3d value=%f now=%llu",
-                    event->delta_time, cev->ctype, cev->value, gsl_tick_stamp());
+                    event->delta_time, cev->ctype, cev->value, Bse::TickStamp::current());
         }
       node++;
     }
diff --git a/bse/bsesequencer.hh b/bse/bsesequencer.hh
index 5a4c289..b2b7ef7 100644
--- a/bse/bsesequencer.hh
+++ b/bse/bsesequencer.hh
@@ -2,12 +2,17 @@
 #ifndef __BSE_SSEQUENCER_H__
 #define __BSE_SSEQUENCER_H__
 #include <bse/bsesong.hh>
+
 G_BEGIN_DECLS
+
 typedef struct {
   guint64               stamp; /* sequencer time (ahead of real time) */
   SfiRing              *songs;
 } BseSequencer;
-extern BirnetThread       *bse_sequencer_thread;
+
+extern BirnetThread*    bse_sequencer_thread; // FIXME
+
+void                   bse_sequencer_wakeup            ();
 void                   bse_sequencer_init_thread       (void);
 void                    bse_sequencer_add_io_watch      (guint           n_pfds,
                                                          const GPollFD  *pfds,
@@ -19,5 +24,7 @@ void                  bse_sequencer_start_song        (BseSong        *song,
                                                          guint64         start_stamp);
 void                    bse_sequencer_remove_song      (BseSong        *song);
 gboolean                bse_sequencer_thread_lagging    (guint           n_blocks);
+
 G_END_DECLS
+
 #endif /* __BSE_SSEQUENCER_H__ */
diff --git a/bse/bsesong.proc b/bse/bsesong.proc
index 16da96b..5cf9a50 100644
--- a/bse/bsesong.proc
+++ b/bse/bsesong.proc
@@ -417,7 +417,7 @@ METHOD (BseSong, synthesize-note) {
     {
       double semitone_factor = bse_transpose_factor (self->musical_tuning, CLAMP (note, SFI_MIN_NOTE, 
SFI_MAX_NOTE) - SFI_KAMMER_NOTE);
       double freq = BSE_KAMMER_FREQUENCY * semitone_factor * bse_cent_tune_fast (fine_tune);
-      SfiTime tstamp = gsl_tick_stamp () + bse_engine_block_size () * 2;
+      SfiTime tstamp = Bse::TickStamp::current() + bse_engine_block_size () * 2;
       BseMidiEvent *eon, *eoff;
       eon  = bse_midi_event_note_on (track->midi_channel_SL, tstamp, freq, velocity);
       eoff = bse_midi_event_note_off (track->midi_channel_SL, tstamp + duration, freq);
diff --git a/bse/bsewaveosc.cc b/bse/bsewaveosc.cc
index d7fbf4a..4daa3af 100644
--- a/bse/bsewaveosc.cc
+++ b/bse/bsewaveosc.cc
@@ -409,7 +409,7 @@ pcm_pos_access (BseModule *module,      /* EngineThread */
 {
   GslWaveOscData *wosc = (GslWaveOscData*) module->user_data;
   PcmPos *pos = (PcmPos*) data;
-  pos->stamp = GSL_TICK_STAMP;
+  pos->stamp = Bse::TickStamp::current();
   pos->module_pcm_position = gsl_wave_osc_cur_pos (wosc);
   if (pos->perc >= 0 && wosc->wchunk)
     {
diff --git a/bse/gslcommon.cc b/bse/gslcommon.cc
index ed6b80f..d49b569 100644
--- a/bse/gslcommon.cc
+++ b/bse/gslcommon.cc
@@ -11,12 +11,48 @@
 #include <sys/poll.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-/* --- variables --- */
-volatile guint64     bse_engine_exvar_tick_stamp = 0;   /* initialized to 1 upon gsl_init(), so 0==invalid */
-static guint64      tick_stamp_system_time = 0;
-static guint         global_tick_stamp_leaps = 0;
-/* --- tick stamps --- */
-static BirnetMutex     global_tick_stamp_mutex = { 0, };
+
+namespace Bse {
+
+// == TickStamp ==
+static Rapicorn::Mutex          global_tick_stamp_mutex;
+static uint64                  tick_stamp_system_time = 0;
+static uint64                   tick_stamp_leaps = 0;
+Rapicorn::Atomic<uint64>        TickStamp::global_tick_stamp = 0;       // initialized to 1 from gsl_init(), 
so 0 == invalid
+static std::list<TickStampWakeupP> tick_stamp_wakeups;
+
+void
+TickStamp::_init_forgsl()
+{
+  g_return_if_fail (global_tick_stamp == 0);    // assert we're uninitialized
+  global_tick_stamp = 1;
+}
+
+void
+TickStamp::_set_leap (uint64 ticks)
+{
+  Rapicorn::ScopedLock<Rapicorn::Mutex> locker (global_tick_stamp_mutex);
+  tick_stamp_leaps = ticks;
+}
+
+void
+TickStamp::_increment ()
+{
+  g_return_if_fail (tick_stamp_leaps > 0);
+  volatile guint64 newstamp;
+  uint64 systime;
+  systime = sfi_time_system ();
+  newstamp = global_tick_stamp + tick_stamp_leaps;
+  {
+    Rapicorn::ScopedLock<Rapicorn::Mutex> locker (global_tick_stamp_mutex);
+    global_tick_stamp = newstamp;
+    tick_stamp_system_time = systime;
+  }
+  struct Internal : Wakeup { using Wakeup::_emit_wakeups; };
+  Internal::_emit_wakeups (newstamp);
+}
+
+#ifdef  RAPICORN_DOXYGEN
 /**
  * @return GSL's execution tick stamp as unsigned 64bit integer
  *
@@ -29,74 +65,109 @@ static BirnetMutex     global_tick_stamp_mutex = { 0, };
  * sfi_thread_awake_before(). Tick stamp updating occours at
  * GSL engine block processing boundaries, so code that can
  * guarantee to not run across those boundaries (for instance
- * BseProcessFunc() functions) may use the macro GSL_TICK_STAMP
+ * BseProcessFunc() functions) may use the macro Bse::TickStamp::current()
  * to retrieve the current tick in a faster manner (not involving
  * mutex locking). See also bse_module_tick_stamp().
  * This function is MT-safe and may be called from any thread.
  */
-guint64
-gsl_tick_stamp (void)
-{
-  guint64 stamp;
-  GSL_SPIN_LOCK (&global_tick_stamp_mutex);
-  stamp = bse_engine_exvar_tick_stamp;
-  GSL_SPIN_UNLOCK (&global_tick_stamp_mutex);
-  return stamp;
-}
-void
-_gsl_tick_stamp_set_leap (guint ticks)
-{
-  GSL_SPIN_LOCK (&global_tick_stamp_mutex);
-  global_tick_stamp_leaps = ticks;
-  GSL_SPIN_UNLOCK (&global_tick_stamp_mutex);
-}
+uint64 TickStamp::current () { ... }
+#endif
+
 /**
  * @return Current tick stamp and system time in micro seconds
  *
  * Get the system time of the last GSL global tick stamp update.
  * This function is MT-safe and may be called from any thread.
  */
-GslTickStampUpdate
-gsl_tick_stamp_last (void)
+TickStamp::Update
+TickStamp::get_last()
 {
-  GslTickStampUpdate ustamp;
-  GSL_SPIN_LOCK (&global_tick_stamp_mutex);
-  ustamp.tick_stamp = bse_engine_exvar_tick_stamp;
+  Update ustamp;
+  Rapicorn::ScopedLock<Rapicorn::Mutex> locker (global_tick_stamp_mutex);
+  ustamp.tick_stamp = global_tick_stamp;
   ustamp.system_time = tick_stamp_system_time;
-  GSL_SPIN_UNLOCK (&global_tick_stamp_mutex);
   return ustamp;
 }
+
+TickStamp::Wakeup::Wakeup (const std::function<void()> &wakeup) :
+  wakeup_ (wakeup), awake_stamp_ (0)
+{}
+
+TickStampWakeupP
+TickStamp::create_wakeup (const std::function<void()> &wakeup)
+{
+  struct WakeupImpl : TickStamp::Wakeup {
+    WakeupImpl (const std::function<void()> &wakeup) :
+      Wakeup (wakeup)
+    {}
+  };
+  auto wp = std::make_shared<WakeupImpl> (wakeup);
+  return wp;
+}
+
+/**
+ * @param stamp stamp to trigger wakeup
+ *
+ * Wake the current thread up at a future tick increment which exceeds @a stamp.
+ */
 void
-_gsl_tick_stamp_inc (void)
+TickStamp::Wakeup::awake_after (uint64 stamp)
 {
-  volatile guint64 newstamp;
-  guint64 systime;
-  g_return_if_fail (global_tick_stamp_leaps > 0);
-  systime = sfi_time_system ();
-  newstamp = bse_engine_exvar_tick_stamp + global_tick_stamp_leaps;
-  GSL_SPIN_LOCK (&global_tick_stamp_mutex);
-  bse_engine_exvar_tick_stamp = newstamp;
-  tick_stamp_system_time = systime;
-  GSL_SPIN_UNLOCK (&global_tick_stamp_mutex);
-  sfi_thread_emit_wakeups (newstamp);
+  Rapicorn::ScopedLock<Rapicorn::Mutex> locker (global_tick_stamp_mutex);
+  if (!awake_stamp_ && stamp)
+    {
+      tick_stamp_wakeups.push_back (shared_from_this());
+      awake_stamp_ = stamp;
+    }
+  else if (!stamp && awake_stamp_)
+    {
+      tick_stamp_wakeups.remove (shared_from_this());
+      awake_stamp_ = 0;
+    }
+  else if (awake_stamp_ && stamp)
+    awake_stamp_ = MIN (awake_stamp_, stamp);
 }
+
 /**
- * @param tick_stamp tick stamp update to trigger wakeup
+ * @param stamp tick stamp update to trigger wakeup
+ *
  * Wakeup the currently running thread upon the last global tick stamp
- * update (see gsl_tick_stamp()) that happens prior to updating the
+ * update (see Bse::TickStamp::current()) that happens prior to updating the
  * global tick stamp to @a tick_stamp.
  * (If the moment of wakeup has already passed by, the thread is
  * woken up at the next global tick stamp update.)
  */
 void
-gsl_thread_awake_before (guint64 tick_stamp)
+TickStamp::Wakeup::awake_before (uint64 stamp)
 {
-  g_return_if_fail (tick_stamp > 0);
-  if (tick_stamp > global_tick_stamp_leaps)
-    sfi_thread_awake_after (tick_stamp - global_tick_stamp_leaps);
-  else
-    sfi_thread_awake_after (tick_stamp);
+  g_return_if_fail (stamp > 0);
+  if (stamp > tick_stamp_leaps)
+    stamp -= tick_stamp_leaps;
+  awake_after (stamp);
+}
+
+void
+TickStamp::Wakeup::_emit_wakeups (uint64 wakeup_stamp)
+{
+  Rapicorn::ScopedLock<Rapicorn::Mutex> locker (global_tick_stamp_mutex);
+  std::list<TickStampWakeupP> list, notifies;
+  list.swap (tick_stamp_wakeups);
+  for (auto it : list)
+    if (it->awake_stamp_ > wakeup_stamp)
+      tick_stamp_wakeups.push_back (it);
+    else // awake_stamp_ <= wakeup_stamp
+      notifies.push_back (it);
+  for (auto it : notifies)
+    if (it->wakeup_)
+      {
+        it->awake_stamp_ = 0;
+        it->wakeup_();
+      }
 }
+
+} // Bse
+
+
 /* --- misc --- */
 const gchar*
 gsl_byte_order_to_string (guint byte_order)
@@ -310,10 +381,10 @@ gsl_progress_printerr (gpointer          message,
 void
 gsl_init (void)
 {
-  g_return_if_fail (bse_engine_exvar_tick_stamp == 0);  /* assert single initialization */
-  bse_engine_exvar_tick_stamp = 1;
+  g_return_if_fail (Bse::TickStamp::current() == 0);     // assert single initialization
+  struct Internal : Bse::TickStamp { using TickStamp::_init_forgsl; };
+  Internal::_init_forgsl();
   /* initialize subsystems */
-  sfi_mutex_init (&global_tick_stamp_mutex);
   _gsl_init_fd_pool ();
   _gsl_init_data_caches ();
   _gsl_init_loader_gslwave ();
diff --git a/bse/gslcommon.hh b/bse/gslcommon.hh
index 96c53c4..54093a4 100644
--- a/bse/gslcommon.hh
+++ b/bse/gslcommon.hh
@@ -6,21 +6,12 @@
 G_BEGIN_DECLS
 /* --- initialization --- */
 void                   gsl_init        (void);
-/* --- tick stamps --- */
-typedef struct {
-  guint64 tick_stamp;
-  guint64 system_time;
-} GslTickStampUpdate;
-guint64                   gsl_tick_stamp       (void);
-guint64                   gsl_time_system      (void);
-GslTickStampUpdate gsl_tick_stamp_last (void);
-#define                   GSL_TICK_STAMP       (_GSL_TICK_STAMP_VAL ())
-#define                   GSL_MAX_TICK_STAMP   (18446744073709551615LLU /* 2^64-1*/)
-void           gsl_thread_awake_before (guint64         tick_stamp);
+
 #define        GSL_SPIN_LOCK   sfi_mutex_lock
 #define        GSL_SPIN_UNLOCK sfi_mutex_unlock
 #define        GSL_SYNC_LOCK   sfi_mutex_lock
 #define        GSL_SYNC_UNLOCK sfi_mutex_unlock
+
 /* --- misc --- */
 const gchar* gsl_byte_order_to_string   (guint           byte_order);
 guint        gsl_byte_order_from_string (const gchar    *string);
@@ -39,7 +30,8 @@ typedef guint (*GslProgressFunc)        (gpointer          data,
                                          GslProgressState *pstate);
 struct _GslProgressState
 {
-  guint           wipe_length, precision;
+  uint            wipe_length;
+  int             precision;
   gfloat          pval, epsilon;
   gpointer        pdata;
   GslProgressFunc pfunc;
@@ -57,8 +49,6 @@ guint            gsl_progress_printerr  (gpointer          message,
                                          const gchar      *detail,
                                          GslProgressState *pstate);
 /* --- implementation details --- */
-void          _gsl_tick_stamp_inc      (void);
-void          _gsl_tick_stamp_set_leap (guint           ticks);
 void   _gsl_init_fd_pool               (void);
 void   _gsl_init_data_caches           (void);
 void   _gsl_init_loader_gslwave        (void);
@@ -68,7 +58,42 @@ void _gsl_init_loader_oggvorbis      (void);
 void   _gsl_init_loader_mad            (void);
 void   bse_init_loader_gus_patch       (void);
 #define                GSL_N_IO_RETRIES        (5)
-#define                _GSL_TICK_STAMP_VAL()   (bse_engine_exvar_tick_stamp + 0)
-extern volatile guint64        bse_engine_exvar_tick_stamp;
 G_END_DECLS
+
+
+namespace Bse {
+
+// == TickStamp ==
+class TickStamp {
+  static Rapicorn::Atomic<uint64> global_tick_stamp;
+protected:
+  static void           _init_forgsl  ();
+public:
+  class Wakeup : public std::enable_shared_from_this<Wakeup> {
+    std::function<void()> wakeup_;
+    uint64                awake_stamp_;
+  protected:
+    explicit            Wakeup (const std::function<void()> &wakeup);
+    static void         _emit_wakeups   (uint64 wakeup_stamp);
+  public:
+    void                awake_after     (uint64 stamp);
+    void                awake_before    (uint64 stamp);
+  };
+  typedef std::shared_ptr<Wakeup> WakeupP;
+  struct Update {
+    uint64 tick_stamp;
+    uint64 system_time;
+  };
+  static Update         get_last        ();
+  static WakeupP        create_wakeup   (const std::function<void()> &wakeup);
+  static inline uint64  current         ()      { return global_tick_stamp; }
+  static inline uint64  max_stamp       ()      { return 18446744073709551615LLU; } ///< Maximum stamp 
value, 2^64-1.
+  static void          _increment      ();
+  static void          _set_leap       (uint64 ticks);
+};
+typedef TickStamp::WakeupP TickStampWakeupP;
+
+} // Bse
+
+
 #endif /* __GSL_COMMON_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]