Skip to content

Commit 1968b9d

Browse files
committed
[core] improve accuracy and make configurable the reactor timeout
The timeout accuracy for the async script operations depends on the value of the I/O reactor timeout (how often the reactor can check for timeout events). In order to cope with 1 second async timeout, we need a much lower reactor timeout -> the reactor timeout was moved from seconds to miliseconds Also this reactor timeout can not be configurable via script param, see the new `worker_reactor_timeout` core parameter. This takes values between 100 and 1000 ms.
1 parent d2e9ffc commit 1968b9d

19 files changed

Lines changed: 784 additions & 56 deletions

‎cfg.lex‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ MEMLOG "memlog"|"mem_log"
248248
MEMDUMP "memdump"|"mem_dump"
249249
SHM_MEMLOG_SIZE "shm_memlog_size"
250250
EXECMSGTHRESHOLD "execmsgthreshold"|"exec_msg_threshold"
251+
WORKER_REACTOR_TIMEOUT "workerreactortimeout"|"worker_reactor_timeout"
251252
EXECDNSTHRESHOLD "execdnsthreshold"|"exec_dns_threshold"
252253
TCPTHRESHOLD "tcpthreshold"|"tcp_threshold"
253254
EVENT_SHM_THRESHOLD "event_shm_threshold"
@@ -482,6 +483,7 @@ SPACE [ ]
482483
<INITIAL>{MEMDUMP} { count(); yylval.strval=yytext; return MEMDUMP; }
483484
<INITIAL>{SHM_MEMLOG_SIZE} { count(); yylval.strval=yytext; return SHM_MEMLOG_SIZE; }
484485
<INITIAL>{EXECMSGTHRESHOLD} { count(); yylval.strval=yytext; return EXECMSGTHRESHOLD; }
486+
<INITIAL>{WORKER_REACTOR_TIMEOUT} { count(); yylval.strval=yytext; return WORKER_REACTOR_TIMEOUT; }
485487
<INITIAL>{EXECDNSTHRESHOLD} { count(); yylval.strval=yytext; return EXECDNSTHRESHOLD; }
486488
<INITIAL>{TCPTHRESHOLD} { count(); yylval.strval=yytext; return TCPTHRESHOLD; }
487489
<INITIAL>{EVENT_SHM_THRESHOLD} { count(); yylval.strval=yytext; return EVENT_SHM_THRESHOLD; }

‎cfg.y‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
#include "config.h"
112112
#include "mem/rpm_mem.h"
113113
#include "poll_types.h"
114+
#include "reactor_defs.h"
114115

115116
#ifdef SHM_EXTRA_STATS
116117
#include "mem/module_info.h"
@@ -354,6 +355,7 @@ extern int cfg_parse_only_routes;
354355
%token MEMDUMP
355356
%token SHM_MEMLOG_SIZE
356357
%token EXECMSGTHRESHOLD
358+
%token WORKER_REACTOR_TIMEOUT
357359
%token EXECDNSTHRESHOLD
358360
%token TCPTHRESHOLD
359361
%token EVENT_SHM_THRESHOLD
@@ -1259,6 +1261,8 @@ assign_stm: LOGLEVEL EQUAL snumber { IFOR();
12591261
| MEMDUMP EQUAL error { yyerror("int value expected"); }
12601262
| EXECMSGTHRESHOLD EQUAL NUMBER { IFOR();execmsgthreshold=$3; }
12611263
| EXECMSGTHRESHOLD EQUAL error { yyerror("int value expected"); }
1264+
| WORKER_REACTOR_TIMEOUT EQUAL NUMBER { IFOR(); worker_reactor_timeout=$3; }
1265+
| WORKER_REACTOR_TIMEOUT EQUAL error { yyerror("int value expected"); }
12621266
| EXECDNSTHRESHOLD EQUAL NUMBER { IFOR(); execdnsthreshold=$3; }
12631267
| EXECDNSTHRESHOLD EQUAL error { yyerror("int value expected"); }
12641268
| TCPTHRESHOLD EQUAL NUMBER { IFOR(); tcpthreshold=$3; }

‎docs/manual/Script-CoreParameters.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,21 @@ wdir = "/usr/local/opensips"
15051505
wdir = /usr/opensips_wd
15061506
```
15071507

1508+
### worker_reactor_timeout
1509+
1510+
The timeout, in milliseconds, used by the internal I/O reactor in OpenSIPS worker processes. This is relevant for the timeout of the async operations. If you use low timeout values in your script async operations or you want these timeouts to be really accurate, you should lower this reactor timeout (so it can check more often for the async timeout jobs). If your aync timouts are high and precision is not a key concern, you can keep the the default of 1 second setting.
1511+
1512+
By `worker` processes we do understand processes handling SIP traffic or SIP operations - shortly this impacts the UDP, TCP and TIMER related processes.
1513+
1514+
Default value is `1000` milliseconds. Values lower than `100` are rounded up to `100`; values higher than `1000` are rounded down to `1000`.
1515+
1516+
Example of usage:
1517+
```opensips
1518+
1519+
worker_reactor_timeout = 500
1520+
1521+
```
1522+
15081523
### xlog_buf_size
15091524

15101525
Size of the buffer used to print a single line through the selected **OpenSIPS** logging facility. If the buffer is too small, an overflow error will be printed and the line will be skipped. The default value is `4096` bytes.

‎io_wait.h‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ struct fd_map {
114114
* internal usage */
115115
int app_flags; /* flags to be used by upper layer apps, not by
116116
* the reactor */
117-
unsigned int timeout;
117+
utime_t timeout;
118118
};
119119

120120

@@ -219,7 +219,7 @@ static inline struct fd_map* hash_fd_map( io_wait_h* h,
219219
fd_type type,
220220
void* data,
221221
int flags,
222-
unsigned int timeout,
222+
utime_t timeout,
223223
int *already)
224224
{
225225
if (h->fd_hash[fd].fd <= 0) {
@@ -367,7 +367,7 @@ inline static int io_watch_add( io_wait_h* h, // lgtm [cpp/use-of-goto]
367367
fd_type type,
368368
void* data,
369369
int prio,
370-
unsigned int timeout,
370+
utime_t timeout,
371371
int flags)
372372
{
373373

@@ -474,8 +474,9 @@ inline static int io_watch_add( io_wait_h* h, // lgtm [cpp/use-of-goto]
474474
return 0;
475475
}
476476

477+
/* convert timeout from seconds to miliseconds*/
477478
if (timeout)
478-
timeout+=get_ticks();
479+
timeout = timeout*1000000 + get_uticks();
479480

480481
if ((e=hash_fd_map(h, fd, type, data,flags, timeout, &already))==0){
481482
LM_ERR("[%s] failed to hash the fd %d\n",h->name, fd);

‎io_wait_loop.h‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ static int handle_io(struct fd_map* fm, int idx,int event_type) {
6262
/*! \brief io_wait_loop_x style function
6363
* wait for io using poll()
6464
* \param h io_wait handle
65-
* \param t timeout in s
65+
* \param t timeout in ms
6666
* \param repeat if !=0 handle_io will be called until it returns <=0
6767
* \return number of IO events handled on success (can be 0), -1 on error
6868
*/
@@ -74,7 +74,7 @@ inline static int io_wait_loop_poll(io_wait_h* h, int t, int repeat)
7474
unsigned int curr_time;
7575

7676
again:
77-
ret=n=poll(h->fd_array, h->fd_no, t*1000);
77+
ret=n=poll(h->fd_array, h->fd_no, t);
7878
if (n==-1){
7979
if (errno==EINTR) goto again; /* signal, ignore it */
8080
else{
@@ -136,8 +136,8 @@ inline static int io_wait_loop_select(io_wait_h* h, int t, int repeat)
136136

137137
again:
138138
sel_set=h->master_set;
139-
timeout.tv_sec=t;
140-
timeout.tv_usec=0;
139+
timeout.tv_sec=t/1000;
140+
timeout.tv_usec=(t%1000)*1000;
141141
ret=n=select(h->max_fd_select+1, &sel_set, 0, 0, &timeout);
142142
if (n<0){
143143
if (errno==EINTR) goto again; /* just a signal */
@@ -172,25 +172,25 @@ inline static int io_wait_loop_epoll(io_wait_h* h, int t, int repeat)
172172
struct fd_map *e;
173173
struct epoll_event ep_event;
174174
int fd;
175-
unsigned int curr_time;
175+
utime_t curr_time;
176176

177177
again:
178-
ret=n=epoll_wait(h->epfd, h->ep_array, h->fd_no, t*1000);
178+
ret=n=epoll_wait(h->epfd, h->ep_array, h->fd_no, t);
179179
if (n==-1){
180180
if (errno == EINTR) {
181181
goto again; /* signal, ignore it */
182182
} else if (h->fd_no == 0) {
183-
sleep(t);
183+
poll(NULL, 0, t);
184184
return 0;
185185
} else {
186186
LM_ERR("[%s] epoll_wait(%d, %p, %d, %d): %s [%d]\n",
187-
h->name,h->epfd, h->ep_array, h->fd_no, t*1000,
187+
h->name,h->epfd, h->ep_array, h->fd_no, t,
188188
strerror(errno), errno);
189189
goto error;
190190
}
191191
}
192192

193-
curr_time = get_ticks();
193+
curr_time = get_uticks();
194194

195195
for (r=0; r<n; r++) {
196196
#if 0
@@ -327,8 +327,8 @@ inline static int io_wait_loop_kqueue(io_wait_h* h, int t, int repeat)
327327
struct fd_map *e;
328328
unsigned int curr_time;
329329

330-
tspec.tv_sec=t;
331-
tspec.tv_nsec=0;
330+
tspec.tv_sec=t/1000;
331+
tspec.tv_nsec=(t%1000)*1000000;
332332
again:
333333
ret=n=kevent(h->kq_fd, h->kq_changes, h->kq_nchanges, h->kq_array,
334334
h->fd_no, &tspec);
@@ -397,8 +397,8 @@ inline static int io_wait_loop_sigio_rt(io_wait_h* h, int t)
397397
struct fd_map* fm;
398398

399399
ret=1; /* 1 event per call normally */
400-
ts.tv_sec=t;
401-
ts.tv_nsec=0;
400+
ts.tv_sec=t/1000;
401+
ts.tv_nsec=(t%1000)*1000000;
402402
if (!sigismember(&h->sset, h->signo) || !sigismember(&h->sset, SIGIO)){
403403
LM_CRIT("[%s] the signal mask is not properly set!\n",h->name);
404404
goto error;
@@ -505,7 +505,7 @@ inline static int io_wait_loop_devpoll(io_wait_h* h, int t, int repeat)
505505
struct fd_map *e;
506506
unsigned int curr_time;
507507

508-
dpoll.dp_timeout=t*1000;
508+
dpoll.dp_timeout=t;
509509
dpoll.dp_nfds=h->fd_no;
510510
dpoll.dp_fds=h->dp_changes;
511511
again:

‎modules/event_kafka/kafka_producer.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
#define F_KAFKA_JOB -3 /* new job from an worker process */
4646
#define F_KAFKA_EVENT -4 /* new event in librdkafka main event queue */
4747

48-
#define KAFKA_REACTOR_TIMEOUT 1
48+
#define KAFKA_REACTOR_TIMEOUT 1000 /* ms */
4949

5050
void dr_msg_cb(rd_kafka_t *rk, const rd_kafka_message_t *rkmessage, void *opaque);
5151

‎modules/event_stream/stream_send.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
#define JSONRPC_REQ_NEW 0
3939
#define JSONRPC_REQ_SENT 1
40-
#define STREAM_REACTOR_TIMEOUT 1 /* sec */
40+
#define STREAM_REACTOR_TIMEOUT 1000 /* ms */
4141
#define STREAM_MAX_PENDING_READS 4
4242
#define IS_ERR(_err) (errno == _err)
4343
#define STREAM_ADDR(con) \

‎modules/freeswitch/fs_proc.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#include "fs_api.h"
3838
#include "fs_ipc.h"
3939

40-
#define FS_REACTOR_TIMEOUT 1 /* sec */
40+
#define FS_REACTOR_TIMEOUT 1000 /* ms */
4141
#define FS_STATS_EVENT_NAME "HEARTBEAT"
4242

4343
extern struct list_head *fs_sockets;

‎net/net_tcp_proc.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ int tcp_worker_proc_reactor_init( int unix_sock)
275275
void tcp_worker_proc_loop(void)
276276
{
277277
/* main loop */
278-
reactor_main_loop(TCP_CHILD_SELECT_TIMEOUT, error,);
278+
reactor_main_loop( worker_reactor_timeout, error,);
279279
LM_CRIT("exiting...");
280280
exit(-1);
281281
error:

‎net/net_udp.c‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
#include "net_udp.h"
3838

3939

40-
#define UDP_SELECT_TIMEOUT 1
41-
4240
/* if the UDP network layer is used or not by some protos */
4341
static int udp_disabled = 1;
4442

@@ -442,7 +440,7 @@ static int fork_dynamic_udp_process(void *si_filter)
442440
/* the child proc is done read&write) dealing with the status pipe */
443441
clean_read_pipeend();
444442

445-
reactor_main_loop(UDP_SELECT_TIMEOUT, error, );
443+
reactor_main_loop( worker_reactor_timeout, error, );
446444
destroy_worker_reactor();
447445
error:
448446
report_failure_status();
@@ -567,7 +565,7 @@ int udp_start_processes(int *chd_rank, int *startup_done)
567565
* \see receive_msg
568566
* \see main_loop
569567
*/
570-
reactor_main_loop(UDP_SELECT_TIMEOUT, error, );
568+
reactor_main_loop( worker_reactor_timeout, error, );
571569
destroy_worker_reactor();
572570
exit(-1);
573571
} else {

0 commit comments

Comments
 (0)