289 mb_slave_run(server_node->mb_nd /* nd */, callbacks, server_node->slave_id); |
289 mb_slave_run(server_node->mb_nd /* nd */, callbacks, server_node->slave_id); |
290 fprintf(stderr, "Modbus plugin: Modbus server for node %%s died unexpectedly!\n", server_node->location); /* should never occur */ |
290 fprintf(stderr, "Modbus plugin: Modbus server for node %%s died unexpectedly!\n", server_node->location); /* should never occur */ |
291 return NULL; |
291 return NULL; |
292 } |
292 } |
293 |
293 |
|
294 |
|
295 #define timespec_add(ts, sec, nsec) { \ |
|
296 ts.tv_sec += sec; \ |
|
297 ts.tv_nsec += nsec; \ |
|
298 if (ts.tv_nsec >= 1000000000) { \ |
|
299 ts.tv_sec ++; \ |
|
300 ts.tv_nsec -= 1000000000; \ |
|
301 } \ |
|
302 } |
294 |
303 |
295 |
304 |
296 static void *__mb_client_thread(void *_index) { |
305 static void *__mb_client_thread(void *_index) { |
297 int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) |
306 int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) |
298 struct timespec next_cycle; |
307 struct timespec next_cycle; |
360 break; |
369 break; |
361 } |
370 } |
362 } |
371 } |
363 } |
372 } |
364 // Determine absolute time instant for starting the next cycle |
373 // Determine absolute time instant for starting the next cycle |
365 // struct timespec prev_cycle; |
374 struct timespec prev_cycle, now; |
366 // prev_cycle = next_cycle; |
375 prev_cycle = next_cycle; |
367 next_cycle.tv_sec += period_sec; |
376 timespec_add(next_cycle, period_sec, period_nsec); |
368 next_cycle.tv_nsec += period_nsec; |
377 /* NOTE A: |
369 if (next_cycle.tv_nsec >= 1000000000) { |
378 * When we have difficulty communicating with remote client and/or server, then the communications get delayed and we will |
370 next_cycle.tv_sec ++; |
379 * fall behind in the period. This means that when communication is re-established we may end up running this loop continuously |
371 next_cycle.tv_nsec -= 1000000000; |
380 * for some time until we catch up. |
372 } |
381 * This is undesirable, so we detect it by making sure the next_cycle will start in the future. |
373 /* It probably does not make sense to check for overflow of timer. |
382 * When this happens we will switch from a purely periodic task _activation_ sequence, to a fixed task suspension interval. |
|
383 * |
|
384 * NOTE B: |
|
385 * It probably does not make sense to check for overflow of timer. |
374 * Even in 32 bit systems this will take at least 68 years since the computer booted |
386 * Even in 32 bit systems this will take at least 68 years since the computer booted |
375 * (remember, we are using CLOCK_MONOTONIC, which should start counting from 0 |
387 * (remember, we are using CLOCK_MONOTONIC, which should start counting from 0 |
376 * every time the system boots). On 64 bit systems, it will take over |
388 * every time the system boots). On 64 bit systems, it will take over |
377 * 10^11 years to overflow. |
389 * 10^11 years to overflow. |
378 */ |
390 */ |
379 /* |
391 clock_gettime(CLOCK_MONOTONIC, &now); |
380 if (next_cycle.tv_sec) < prev_cycle.tv_sec) { |
392 if ( ((now.tv_sec > next_cycle.tv_sec) || ((now.tv_sec == next_cycle.tv_sec) && (now.tv_nsec > next_cycle.tv_nsec))) |
381 // we will lose some precision by reading the time again, |
393 /* We are falling behind. See NOTE A above */ |
382 // but it is better than the alternative... |
394 || (next_cycle.tv_sec < prev_cycle.tv_sec) |
383 clock_gettime(CLOCK_MONOTONIC, &next_cycle); |
395 /* Timer overflow. See NOTE B above */ |
384 next_cycle.tv_sec += period_sec; |
396 ) { |
385 next_cycle.tv_nsec += period_nsec; |
397 next_cycle = now; |
386 if (next_cycle.tv_nsec >= 1000000000) { |
398 timespec_add(next_cycle, period_sec, period_nsec); |
387 next_cycle.tv_sec ++; |
399 } |
388 next_cycle.tv_nsec -= 1000000000; |
|
389 } |
|
390 } |
|
391 */ |
|
392 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL); |
400 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL); |
393 } |
401 } |
394 |
402 |
395 // humour the compiler. |
403 // humour the compiler. |
396 return NULL; |
404 return NULL; |