From 26c348411c72dd7901dc77e895f904c26dad45ac Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 12 Jan 2024 18:57:53 +0100 Subject: [PATCH] Datenklo: Timers may only be scheduled or deleted in the main thread Set flags to schedule timers in main thread. Timers are: vtimer (datenklo.c), tx/rx timers (am791x.c) --- src/datenklo/am791x.c | 98 +++++++++++++++++++++++++++++------------ src/datenklo/am791x.h | 2 + src/datenklo/datenklo.c | 18 +++++--- src/datenklo/datenklo.h | 1 + 4 files changed, 86 insertions(+), 33 deletions(-) diff --git a/src/datenklo/am791x.c b/src/datenklo/am791x.c index f2ddf1d..5f3ee1a 100644 --- a/src/datenklo/am791x.c +++ b/src/datenklo/am791x.c @@ -587,7 +587,6 @@ static void set_flag(int *flag_p, int value, const char *name) /* * state machine according to datasheet */ - static void go_main_channel_tx(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Enable transmitter on main channel\n"); @@ -601,7 +600,8 @@ static void go_main_channel_tx(am791x_t *am791x) /* activate TD now and set CTS timer (RCON) */ set_flag(&am791x->block_td, 0, "TD RELEASED"); set_flag(&am791x->tx_silence, 0, "RESET SILENCE"); - osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->t_rcon)); + /* Flag timer, because it must be added in main thread. */ + am791x->tx_timer_f = am791x->t_rcon; new_tx_state(am791x, AM791X_STATE_RCON); set_filters(am791x); /* check CD to be blocked */ @@ -652,7 +652,8 @@ static void tx_data_done(am791x_t *am791x) if (!am791x->fullduplex) { set_flag(&am791x->squelch, 1, "SET SQUELCH (ON)"); } - osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->t_rcoff)); + /* Flag timer, because it must be added in main thread. */ + am791x->tx_timer_f = am791x->t_rcoff; } static void rcoff_done(am791x_t *am791x) @@ -667,11 +668,13 @@ static void rcoff_done(am791x_t *am791x) return; } if (!am791x->sto) { - osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->t_sq - am791x->t_rcoff)); + /* Flag timer, because it must be added in main thread. */ + am791x->tx_timer_f = am791x->t_sq - am791x->t_rcoff; new_tx_state(am791x, AM791X_STATE_SQ_OFF); return; } - osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->t_sto - am791x->t_rcoff)); + /* Flag timer, because it must be added in main thread. */ + am791x->tx_timer_f = am791x->t_sto - am791x->t_rcoff; new_tx_state(am791x, AM791X_STATE_STO_OFF); } @@ -695,7 +698,8 @@ static void sto_done(am791x_t *am791x) LOGP(DAM791X, LOGL_DEBUG, "STO over\n"); set_flag(&am791x->tx_sto, 0, "stop STO"); - osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->t_sq - am791x->t_sto)); + /* Flag timer, because it must be added in main thread. */ + am791x->tx_timer_f = am791x->t_sq - am791x->t_sto; new_tx_state(am791x, AM791X_STATE_SQ_OFF); } @@ -711,7 +715,8 @@ static void go_back_channel_tx(am791x_t *am791x) /* activate BTD now and set BCTS timer (BRCON) */ set_flag(&am791x->block_btd, 0, "BTD RELEASED"); set_flag(&am791x->tx_silence, 0, "RESET SILENCE"); - osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->t_brcon)); + /* Flag timer, because it must be added in main thread. */ + am791x->tx_timer_f = am791x->t_brcon; new_tx_state(am791x, AM791X_STATE_BRCON); set_filters(am791x); /* check BCD to be blocked */ @@ -747,7 +752,8 @@ static void tx_bdata_done(am791x_t *am791x) set_flag(&am791x->block_btd, 1, "BTD IGNORED"); set_flag(&am791x->tx_silence, 1, "SET SILENCE"); - osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->t_brcoff)); + /* Flag timer, because it must be added in main thread. */ + am791x->tx_timer_f = am791x->t_brcoff; } static void brcoff_done(am791x_t *am791x) @@ -793,7 +799,8 @@ static void handle_tx_state(am791x_t *am791x) rcon_release_rts(am791x); break; } - if (!osmo_timer_pending(&am791x->tx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) { rcon_done(am791x); break; } @@ -805,19 +812,22 @@ static void handle_tx_state(am791x_t *am791x) } break; case AM791X_STATE_RCOFF: - if (!osmo_timer_pending(&am791x->tx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) { rcoff_done(am791x); break; } break; case AM791X_STATE_STO_OFF: - if (!osmo_timer_pending(&am791x->tx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) { sto_done(am791x); break; } break; case AM791X_STATE_SQ_OFF: - if (!osmo_timer_pending(&am791x->tx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) { sq_done(am791x); break; } @@ -828,7 +838,8 @@ static void handle_tx_state(am791x_t *am791x) brcon_release_brts(am791x); break; } - if (!osmo_timer_pending(&am791x->tx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) { brcon_done(am791x); break; } @@ -840,7 +851,8 @@ static void handle_tx_state(am791x_t *am791x) } break; case AM791X_STATE_BRCOFF: - if (!osmo_timer_pending(&am791x->tx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->tx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->tx_timer) && am791x->tx_timer_f == 0.0)) { brcoff_done(am791x); break; } @@ -854,7 +866,8 @@ static void go_main_channel_rx(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Enable receiver on main channel\n"); - osmo_timer_schedule(&am791x->rx_timer, FLOAT_TO_TIMEOUT(am791x->t_cdon)); + /* Flag timer, because it must be added in main thread. */ + am791x->rx_timer_f = am791x->t_cdon; new_rx_state(am791x, AM791X_STATE_CDON); } @@ -876,7 +889,8 @@ static void cdon_no_cd(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Carrier is gone\n"); - osmo_timer_del(&am791x->rx_timer); + /* Flag timer, because it must be deleted in main thread. */ + am791x->rx_timer_f = -1; new_rx_state(am791x, AM791X_STATE_INIT); } @@ -884,7 +898,8 @@ static void rx_data_done(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Carrier lost\n"); - osmo_timer_schedule(&am791x->rx_timer, FLOAT_TO_TIMEOUT(am791x->t_cdoff)); + /* Flag timer, because it must be added in main thread. */ + am791x->rx_timer_f = am791x->t_cdoff; new_rx_state(am791x, AM791X_STATE_CDOFF); } @@ -906,7 +921,8 @@ static void cdoff_cd(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Carrier recovered\n"); - osmo_timer_del(&am791x->rx_timer); + /* Flag timer, because it must be deleted in main thread. */ + am791x->rx_timer_f = -1; new_rx_state(am791x, AM791X_STATE_DATA); } @@ -914,7 +930,8 @@ static void go_back_channel_rx(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Enable receiver on back channel\n"); - osmo_timer_schedule(&am791x->rx_timer, FLOAT_TO_TIMEOUT(am791x->t_bcdon)); + /* Flag timer, because it must be added in main thread. */ + am791x->rx_timer_f = am791x->t_bcdon; new_rx_state(am791x, AM791X_STATE_BCDON); } @@ -936,7 +953,8 @@ static void bcdon_no_cd(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Carrier is gone\n"); - osmo_timer_del(&am791x->rx_timer); + /* Flag timer, because it must be deleted in main thread. */ + am791x->rx_timer_f = -1; new_rx_state(am791x, AM791X_STATE_INIT); } @@ -944,7 +962,8 @@ static void rx_bdata_done(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Carrier lost\n"); - osmo_timer_schedule(&am791x->rx_timer, FLOAT_TO_TIMEOUT(am791x->t_bcdoff)); + /* Flag timer, because it must be added in main thread. */ + am791x->rx_timer_f = am791x->t_bcdoff; new_rx_state(am791x, AM791X_STATE_BCDOFF); } @@ -967,7 +986,8 @@ static void bcdoff_cd(am791x_t *am791x) { LOGP(DAM791X, LOGL_DEBUG, "Carrier recovered\n"); - osmo_timer_del(&am791x->rx_timer); + /* Flag timer, because it must be deleted in main thread. */ + am791x->rx_timer_f = -1; new_rx_state(am791x, AM791X_STATE_BDATA); } @@ -994,7 +1014,8 @@ static void handle_rx_state(am791x_t *am791x) break; /* all main channel states ... */ case AM791X_STATE_CDON: - if (!osmo_timer_pending(&am791x->rx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->rx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->rx_timer) && am791x->rx_timer_f == 0.0)) { cdon_done(am791x); break; } @@ -1010,7 +1031,8 @@ static void handle_rx_state(am791x_t *am791x) } break; case AM791X_STATE_CDOFF: - if (!osmo_timer_pending(&am791x->rx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->rx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->rx_timer) && am791x->rx_timer_f == 0.0)) { cdoff_done(am791x); break; } @@ -1021,7 +1043,8 @@ static void handle_rx_state(am791x_t *am791x) break; /* all back channel states ... */ case AM791X_STATE_BCDON: - if (!osmo_timer_pending(&am791x->rx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->rx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->rx_timer) && am791x->rx_timer_f == 0.0)) { bcdon_done(am791x); break; } @@ -1037,7 +1060,8 @@ static void handle_rx_state(am791x_t *am791x) } break; case AM791X_STATE_BCDOFF: - if (!osmo_timer_pending(&am791x->rx_timer)) { + /* If timer is about to be switched off, of if it already has been switched off. */ + if (am791x->rx_timer_f < 0.0 || (!osmo_timer_pending(&am791x->rx_timer) && am791x->rx_timer_f == 0.0)) { bcdoff_done(am791x); break; } @@ -1191,8 +1215,10 @@ void am791x_reset(am791x_t *am791x) { LOGP(DAM791X, LOGL_INFO, "Reset!\n"); - osmo_timer_del(&am791x->tx_timer); - osmo_timer_del(&am791x->rx_timer); + /* Flag timer, because it must be deleted in main thread. */ + am791x->tx_timer_f = -1.0; + /* Flag timer, because it must be deleted in main thread. */ + am791x->rx_timer_f = -1.0; if (am791x->f0_tx) { fsk_mod_cleanup(&am791x->fsk_tx); @@ -1266,3 +1292,19 @@ void am791x_ring(am791x_t *am791x, int ring) handle_state(am791x); } +void am791x_add_del_timers(am791x_t *am791x) +{ + /* Timers may only be processed in main thread, because libosmocore has timer lists for individual threads. */ + if (am791x->tx_timer_f < 0.0) + osmo_timer_del(&am791x->tx_timer); + if (am791x->tx_timer_f > 0.0) + osmo_timer_schedule(&am791x->tx_timer, FLOAT_TO_TIMEOUT(am791x->tx_timer_f)); + am791x->tx_timer_f = 0.0; + + if (am791x->rx_timer_f < 0.0) + osmo_timer_del(&am791x->rx_timer); + if (am791x->rx_timer_f > 0.0) + osmo_timer_schedule(&am791x->rx_timer, FLOAT_TO_TIMEOUT(am791x->rx_timer_f)); + am791x->rx_timer_f = 0.0; +} + diff --git a/src/datenklo/am791x.h b/src/datenklo/am791x.h index 163c1d2..54f1016 100644 --- a/src/datenklo/am791x.h +++ b/src/datenklo/am791x.h @@ -68,6 +68,7 @@ typedef struct am791x { /* timers */ struct osmo_timer_list tx_timer, rx_timer; + double tx_timer_f, rx_timer_f; /* time to stat / flag to stop */ double t_rcon; double t_rcoff; double t_brcon; @@ -104,4 +105,5 @@ void am791x_dtr(am791x_t *am791x, int dtr); void am791x_rts(am791x_t *am791x, int rts); void am791x_brts(am791x_t *am791x, int brts); void am791x_ring(am791x_t *am791x, int ring); +void am791x_add_del_timers(am791x_t *am791x); diff --git a/src/datenklo/datenklo.c b/src/datenklo/datenklo.c index 9a5ff82..2af215c 100644 --- a/src/datenklo/datenklo.c +++ b/src/datenklo/datenklo.c @@ -1093,7 +1093,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags) if (vmin && vtime) { /* first: start timer */ if (!datenklo->vtimeout) - osmo_timer_schedule(&datenklo->vtimer, vtime/10,(vtime % 10) * 100000); + datenklo->vtimer_us = vtime * 100000; /* start timer in main loop */ /* no data: block (in blocking IO) */ if (fill == 0) { /* special value to tell device there is no data right now, we have to block */ @@ -1106,7 +1106,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags) } /* enough data or timeout or nonblocking IO: stop timer and return what we have */ datenklo->vtimeout = 0; - osmo_timer_del(&datenklo->vtimer); + datenklo->vtimer_us = -1; /* stop timer in main loop */ } /* both MIN and TIME are zero */ if (!vmin && !vtime) { @@ -1119,7 +1119,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags) if (!vmin && vtime) { /* first: start timer */ if (!datenklo->vtimeout) - osmo_timer_schedule(&datenklo->vtimer, vtime/10,(vtime % 10) * 100000); + datenklo->vtimer_us = vtime * 100000; /* start timer in main loop */ if (fill == 0) { /* no data and no timeout: block (in blocking IO) */ if (!datenklo->vtimeout) { @@ -1132,7 +1132,7 @@ static ssize_t dk_read(void *inst, char *buf, size_t size, int flags) } /* data: stop timer and return what we have */ datenklo->vtimeout = 0; - osmo_timer_del(&datenklo->vtimer); + datenklo->vtimer_us = -1; /* stop timer in main loop */ } /* MIN is nonzero, TIME is zero */ if (vmin && !vtime) { @@ -1522,7 +1522,15 @@ void datenklo_main(datenklo_t *datenklo, int loopback) if (num_chan > 1) process_auto_rts(datenklo->slave); - /* process timers */ + /* Timers may only be processed in main thread, because libosmocore has timer lists for individual threads. */ + if (datenklo->vtimer_us < 0) + osmo_timer_del(&datenklo->vtimer); + if (datenklo->vtimer_us > 0) + osmo_timer_schedule(&datenklo->vtimer, datenklo->vtimer_us / 1000000,datenklo->vtimer_us % 1000000); + datenklo->vtimer_us = 0; + + am791x_add_del_timers(&datenklo->am791x); + osmo_select_main(1); #ifdef HAVE_ALSA diff --git a/src/datenklo/datenklo.h b/src/datenklo/datenklo.h index 4094338..2ec3a6f 100644 --- a/src/datenklo/datenklo.h +++ b/src/datenklo/datenklo.h @@ -53,6 +53,7 @@ typedef struct datenklo { int auto_rts_cd; /* CD was indicated */ int output_off; /* output stopped by flow control */ struct osmo_timer_list vtimer; /* VTIME timer */ + int vtimer_us; /* time to stat / flag to stop */ int vtimeout; /* when timeout has fired */ /* data fifos */