Skip to content

Commit 09cdbdf

Browse files
committed
hm2_eth: Improve timeout handling
There where three different ways of handling recv timeouts. The reason is probably that SO_RCVTIMEO works only down to 8ms which would create a real time violation. By using ppoll(), timeouts down to 100us work reliably without needing to poll recv with MSG_DONTWAIT. This reduces the CPU load considerably.
1 parent 3699ca9 commit 09cdbdf

6 files changed

Lines changed: 78 additions & 65 deletions

File tree

src/hal/drivers/mesa-hostmot2/hm2_eth.c

Lines changed: 26 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
#include "hm2_eth_net_evl.h"
5555
#endif
5656

57+
#define RECV_TIMEOUT_NON_RT_NS (200 * 1000 * 1000) //200ms for initialisation / non-realtime part
58+
5759
struct kvlist {
5860
struct rtapi_list_head list;
5961
char key[16+1];
@@ -462,12 +464,10 @@ static const char *hm2_8cSS_pin_names[] = {
462464

463465
};
464466

465-
#define READ_PCK_DELAY_NS 10000
466-
467467
static hm2_eth_t boards[MAX_ETH_BOARDS];
468468

469-
static int eth_socket_send(hm2_eth_t *board, const void *buffer, int len, int flags);
470-
static int eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int flags);
469+
static int eth_socket_send(hm2_eth_t *board, const void *buffer, int len);
470+
static int eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns);
471471

472472
/// firewall functions
473473

@@ -799,13 +799,11 @@ int fetch_hwaddr(hm2_eth_t *board, unsigned char buf[6]) {
799799
lbp16_cmd_addr packet;
800800
unsigned char response[6];
801801
LBP16_INIT_PACKET4(packet, 0x4983, 0x0002);
802-
int res = eth_socket_send(board, &packet, sizeof(packet), 0);
802+
int res = eth_socket_send(board, &packet, sizeof(packet));
803803
if(res < 0) return -errno;
804804

805805
int i=0;
806-
do {
807-
res = eth_socket_recv(board, &response, sizeof(response), 0);
808-
} while(++i < 10 && res < 0 && errno == EAGAIN);
806+
res = eth_socket_recv(board, &response, sizeof(response), RECV_TIMEOUT_NON_RT_NS);
809807
if(res < 0) return -errno;
810808

811809
// eeprom order is backwards from arp AF_LOCAL order
@@ -857,21 +855,12 @@ static inline int close_board(hm2_eth_t *board){
857855
return board->close_board(board);
858856
}
859857

860-
static inline int eth_socket_send(hm2_eth_t *board, const void *buffer, int len, int flags){
861-
return board->eth_socket_send(board, buffer, len, flags);
862-
}
863-
864-
static inline int eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int flags){
865-
return board->eth_socket_recv(board, buffer, len, flags);
858+
static inline int eth_socket_send(hm2_eth_t *board, const void *buffer, int len){
859+
return board->eth_socket_send(board, buffer, len);
866860
}
867861

868-
int eth_socket_recv_loop(hm2_eth_t *board, void *buffer, int len, int flags, long timeout) {
869-
long long end = rtapi_get_time() + timeout;
870-
int result;
871-
do {
872-
result = eth_socket_recv(board, buffer, len, flags);
873-
} while(result < 0 && rtapi_get_time() < end);
874-
return result;
862+
static inline int eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns){
863+
return board->eth_socket_recv(board, buffer, len, recv_timeout_ns);
875864
}
876865

877866
/// hm2_eth io functions
@@ -899,19 +888,15 @@ static int hm2_eth_read(hm2_lowlevel_io_t *this, rtapi_u32 addr, void *buffer, i
899888

900889
LBP16_INIT_PACKET4(read_packet, CMD_READ_HOSTMOT2_ADDR32_INCR(size/4), addr & 0xFFFF);
901890

902-
send = eth_socket_send(board, (void*) &read_packet, sizeof(read_packet), 0);
891+
send = eth_socket_send(board, (void*) &read_packet, sizeof(read_packet));
903892
if(send < 0)
904893
LL_PRINT("ERROR: sending packet: %s\n", strerror(errno));
905894
LL_PRINT_IF(debug, "read(%d) : PACKET SENT [CMD:%02X%02X | ADDR: %02X%02X | SIZE: %d]\n", board->read_cnt, read_packet.cmd_hi, read_packet.cmd_lo,
906895
read_packet.addr_lo, read_packet.addr_hi, size);
896+
907897
t1 = rtapi_get_time();
908-
do {
909-
errno = 0;
910-
recv = eth_socket_recv(board, (void*) &tmp_buffer, size, 0);
911-
if(recv < 0) rtapi_delay(READ_PCK_DELAY_NS);
912-
t2 = rtapi_get_time();
913-
i++;
914-
} while ((recv < 0) && ((t2 - t1) < 200*1000*1000));
898+
recv = eth_socket_recv(board, (void*) &tmp_buffer, size, RECV_TIMEOUT_NON_RT_NS);
899+
t2 = rtapi_get_time();
915900

916901
if (recv == 4) {
917902
LL_PRINT_IF(debug, "read(%d) : PACKET RECV [DATA: %08X | SIZE: %d | TRIES: %d | TIME: %llu]\n", board->read_cnt, *tmp_buffer, recv, i, t2 - t1);
@@ -976,7 +961,7 @@ static int hm2_eth_send_queued_reads(hm2_lowlevel_io_t *this) {
976961
board->queue_reads_count++;
977962
board->queue_buff_size += sizeof(board->confirm_rw_cnt);
978963

979-
send = eth_socket_send(board, (void*) &board->read_packet, board->read_packet_ptr - board->read_packet, 0);
964+
send = eth_socket_send(board, (void*) &board->read_packet, board->read_packet_ptr - board->read_packet);
980965
if(send < 0) {
981966
LL_PRINT("ERROR: sending packet: %s\n", strerror(errno));
982967
return 0;
@@ -1037,21 +1022,19 @@ static int hm2_eth_receive_queued_reads(hm2_lowlevel_io_t *this) {
10371022

10381023
if(!board->hal) this->read_time = t1;
10391024
unsigned long long read_deadline = this->read_time + read_timeout;
1040-
do {
1025+
10411026
do_recv_packet:
1042-
errno = 0;
1043-
recv = eth_socket_recv(board, (void*) &tmp_buffer, board->queue_buff_size, MSG_DONTWAIT);
1044-
if(recv < 0) rtapi_delay(READ_PCK_DELAY_NS);
1045-
t2 = rtapi_get_time();
1046-
i++;
1047-
} while (recv != board->queue_buff_size && t2 < read_deadline);
1027+
recv = eth_socket_recv(board, (void*) &tmp_buffer, board->queue_buff_size, read_timeout);
1028+
t2 = rtapi_get_time();
1029+
10481030
if(recv != board->queue_buff_size) {
1031+
LL_PRINT("receive_queued_reads: error (%m) after %llins timeout=%lins\n", t2 - t1, read_timeout);
10491032
hm2_eth_reset_queued_reads(board);
10501033
if(!record_soft_error(board)) return 0;
10511034
return -EAGAIN;
10521035
}
10531036

1054-
LL_PRINT_IF(debug, "enqueue_read(%d) : PACKET RECV [SIZE: %d | TRIES: %d | TIME: %llu]\n", board->read_cnt, recv, i, t2 - t1);
1037+
LL_PRINT_IF(debug, "receive_queued_reads(%d) : PACKET RECV [SIZE: %d | TIME: %llu]\n", board->read_cnt, recv, t2 - t1);
10551038

10561039
for (i = 0; i < board->queue_reads_count; i++) {
10571040
memcpy(board->queue_reads[i].buffer, &tmp_buffer[board->queue_reads[i].from], board->queue_reads[i].size);
@@ -1082,7 +1065,7 @@ static int hm2_eth_reset(hm2_lowlevel_io_t *this) {
10821065
// Make the watchdog timer bite in 1ns from now
10831066
lbp16_cmd_addr_data32 bite_packet;
10841067
LBP16_INIT_PACKET8(bite_packet, CMD_WRITE_HOSTMOT2_ADDR32_INCR(1), HM2_ADDR_WATCHDOG, 0x0001);
1085-
int ret = eth_socket_send(board, (void*) &bite_packet, sizeof(bite_packet), 0);
1068+
int ret = eth_socket_send(board, (void*) &bite_packet, sizeof(bite_packet));
10861069
if(ret < 0) perror("eth_socket_send(bite_packet)");
10871070
return ret < 0 ? -errno : 0;
10881071
}
@@ -1133,7 +1116,7 @@ static int hm2_eth_write(hm2_lowlevel_io_t *this, rtapi_u32 addr, const void *bu
11331116
memcpy(packet.tmp_buffer, buffer, size);
11341117
LBP16_INIT_PACKET4(packet.wr_packet, CMD_WRITE_HOSTMOT2_ADDR32_INCR(size/4), addr & 0xFFFF);
11351118

1136-
send = eth_socket_send(board, (void*) &packet, sizeof(lbp16_cmd_addr) + size, 0);
1119+
send = eth_socket_send(board, (void*) &packet, sizeof(lbp16_cmd_addr) + size);
11371120
if(send < 0)
11381121
LL_PRINT("ERROR: sending packet: %s\n", strerror(errno));
11391122
LL_PRINT_IF(debug, "write(%d): PACKET SENT [CMD:%02X%02X | ADDR: %02X%02X | SIZE: %d]\n", board->write_cnt, packet.wr_packet.cmd_hi, packet.wr_packet.cmd_lo,
@@ -1165,7 +1148,7 @@ static int hm2_eth_send_queued_writes(hm2_lowlevel_io_t *this) {
11651148
board->has_written_cnt = 1;
11661149

11671150
t0 = rtapi_get_time();
1168-
send = eth_socket_send(board, (void*) &board->write_packet, board->write_packet_ptr - board->write_packet, 0);
1151+
send = eth_socket_send(board, (void*) &board->write_packet, board->write_packet_ptr - board->write_packet);
11691152
if(send < 0) {
11701153
LL_PRINT("ERROR: sending packet: %s\n", strerror(errno));
11711154
}
@@ -1220,13 +1203,12 @@ static int hm2_eth_probe(hm2_eth_t *board) {
12201203
char llio_name[16] = {};
12211204

12221205
LBP16_INIT_PACKET4(read_packet, CMD_READ_BOARD_INFO_ADDR16_INCR(16/2), 0);
1223-
send = eth_socket_send(board, (void*) &read_packet, sizeof(read_packet), 0);
1206+
send = eth_socket_send(board, (void*) &read_packet, sizeof(read_packet));
12241207
if(send < 0) {
12251208
LL_PRINT("ERROR: sending packet: %s\n", strerror(errno));
12261209
return -errno;
12271210
}
1228-
recv = eth_socket_recv_loop(board, (void*) &board_name, 16, 0,
1229-
200 * 1000 * 1000);
1211+
recv = eth_socket_recv(board, (void*) &board_name, 16, RECV_TIMEOUT_NON_RT_NS);
12301212
if(recv < 0) {
12311213
LL_PRINT("ERROR: receiving packet: %s\n", strerror(errno));
12321214
return -errno;

src/hal/drivers/mesa-hostmot2/hm2_eth.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ struct hm2_eth_t {
5151
int (*init_board)(hm2_eth_t *board, const char *board_ip);
5252
int (*init_board_realtime)(hm2_eth_t *board);
5353
int (*close_board)(hm2_eth_t *board);
54-
int (*eth_socket_send)(hm2_eth_t *board, const void *buffer, int len, int flags);
55-
int (*eth_socket_recv)(hm2_eth_t *board, void *buffer, int len, int flags);
54+
int (*eth_socket_send)(hm2_eth_t *board, const void *buffer, int len);
55+
int (*eth_socket_recv)(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns);
5656

5757
//Only for evl implementation
5858
bool is_evl_oob_active;

src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#include "hostmot2-lowlevel.h"
4141
#include "hm2_eth_net_evl.h"
42+
#include "hm2_eth_net_posix.h"
4243

4344
#define SEND_TIMEOUT_US 10
4445
#define RECV_TIMEOUT_US 10
@@ -260,7 +261,7 @@ static int check_evl(hm2_eth_t *board) {
260261
}
261262
}
262263

263-
int hm2_evl_eth_socket_send(hm2_eth_t *board, const void *buffer, int len, int flags) {
264+
int hm2_evl_eth_socket_send(hm2_eth_t *board, const void *buffer, int len) {
264265
ssize_t ret = 0;
265266
ret = check_evl(board);
266267
if (ret < 0) {
@@ -273,8 +274,8 @@ int hm2_evl_eth_socket_send(hm2_eth_t *board, const void *buffer, int len, int f
273274

274275
evl_read_clock(EVL_CLOCK_MONOTONIC, &ts_timeout);
275276
ts_timeout.tv_nsec += 1000*SEND_TIMEOUT_US;
276-
while (ts_timeout.tv_nsec >= 1000000000) {
277-
ts_timeout.tv_nsec -= 1000000000;
277+
while (ts_timeout.tv_nsec >= 1e9) {
278+
ts_timeout.tv_nsec -= 1e9;
278279
ts_timeout.tv_sec ++;
279280
}
280281

@@ -290,17 +291,19 @@ int hm2_evl_eth_socket_send(hm2_eth_t *board, const void *buffer, int len, int f
290291
/*msghdr.msg_name = NULL;
291292
msghdr.msg_namelen = 0;*/
292293
msghdr.msg_flags = 0;
293-
ret = oob_sendmsg(board->sockfd, &msghdr, &ts_timeout, flags);
294+
ret = oob_sendmsg(board->sockfd, &msghdr, &ts_timeout, 0);
294295
if (ret == -1) {
295296
LL_PRINT("ERROR: oob_sendmsg %m %i %li\n", errno, ret);
296297
}
297298
} else {
298-
ret = send(board->sockfd, buffer, len, flags);
299+
//While initialisation, use posix mode due
300+
//to we are not in an evl thread
301+
ret = hm2_posix_eth_socket_send(board, buffer, len);
299302
}
300303
return ret;
301304
}
302305

303-
int hm2_evl_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int flags) {
306+
int hm2_evl_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns) {
304307
ssize_t ret = 0;
305308
ret = check_evl(board);
306309
if (ret < 0) {
@@ -312,9 +315,9 @@ int hm2_evl_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int flags)
312315
struct timespec ts_timeout;
313316

314317
evl_read_clock(EVL_CLOCK_MONOTONIC, &ts_timeout);
315-
ts_timeout.tv_nsec += 1000*RECV_TIMEOUT_US;
316-
while (ts_timeout.tv_nsec >= 1000000000) {
317-
ts_timeout.tv_nsec -= 1000000000;
318+
ts_timeout.tv_nsec += recv_timeout_ns;
319+
while (ts_timeout.tv_nsec >= 1e9) {
320+
ts_timeout.tv_nsec -= 1e9;
318321
ts_timeout.tv_sec ++;
319322
}
320323

@@ -330,9 +333,11 @@ int hm2_evl_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int flags)
330333
/*msghdr.msg_name = NULL;
331334
msghdr.msg_namelen = 0;*/
332335
msghdr.msg_flags = 0;
333-
ret = oob_recvmsg(board->sockfd, &msghdr, &ts_timeout, flags);
336+
ret = oob_recvmsg(board->sockfd, &msghdr, &ts_timeout, 0);
334337
} else {
335-
ret = recv(board->sockfd, buffer, len, flags);
338+
//While initialisation, use posix mode due
339+
//to we are not in an evl thread
340+
ret = hm2_posix_eth_socket_recv(board, buffer, len, recv_timeout_ns);
336341
}
337342
return ret;
338343
}

src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip);
2929
int hm2_evl_init_board_realtime(hm2_eth_t *board);
3030
int hm2_evl_close_board(hm2_eth_t *board);
31-
int hm2_evl_eth_socket_send(hm2_eth_t *board, const void *buffer, int len, int flags);
32-
int hm2_evl_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int flags);
31+
int hm2_evl_eth_socket_send(hm2_eth_t *board, const void *buffer, int len);
32+
int hm2_evl_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns);
3333

3434
#endif

src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <errno.h>
2626
#include <unistd.h>
2727
#include <string.h>
28+
#include <poll.h>
2829

2930
#include <rtapi.h>
3031
#include <rtapi_string.h>
@@ -156,10 +157,35 @@ int hm2_posix_close_board(hm2_eth_t *board) {
156157
return ret < 0 ? -errno : 0;
157158
}
158159

159-
int hm2_posix_eth_socket_send(hm2_eth_t *board, const void *buffer, int len, int flags) {
160-
return send(board->sockfd, buffer, len, flags);
160+
int hm2_posix_eth_socket_send(hm2_eth_t *board, const void *buffer, int len) {
161+
return send(board->sockfd, buffer, len, 0);
161162
}
162163

163-
int hm2_posix_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int flags) {
164-
return recv(board->sockfd, buffer, len, flags);
164+
int hm2_posix_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns) {
165+
struct pollfd pfd;
166+
struct timespec ts;
167+
int ret;
168+
169+
//SO_RCVTIMEO only delivers a timeout down to ~10ms
170+
//while ppoll() works down to 100us
171+
pfd.fd=board->sockfd;
172+
pfd.events = POLLIN;
173+
ts.tv_sec = 0;
174+
ts.tv_nsec = recv_timeout_ns;
175+
while (ts.tv_nsec >= 1e9) {
176+
ts.tv_nsec -= 1e9;
177+
ts.tv_sec ++;
178+
}
179+
ret = ppoll(&pfd, 1, &ts, NULL);
180+
181+
if (ret < 0) {
182+
LL_PRINT("ERROR: ppoll() failed: %m\n");
183+
} else if(ret) {
184+
ret = recv(board->sockfd, buffer, len, 0);
185+
} else {
186+
errno = EAGAIN;
187+
ret = -1;
188+
}
189+
190+
return ret;
165191
}

src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip);
2626
int hm2_posix_init_board_realtime(hm2_eth_t *board);
2727
int hm2_posix_close_board(hm2_eth_t *board);
28-
int hm2_posix_eth_socket_send(hm2_eth_t *board, const void *buffer, int len, int flags);
29-
int hm2_posix_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int flags);
28+
int hm2_posix_eth_socket_send(hm2_eth_t *board, const void *buffer, int len);
29+
int hm2_posix_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns);
3030

3131
#endif

0 commit comments

Comments
 (0)