bugfix: lock bug & udp direct write

This commit is contained in:
Cloud Wu
2017-06-19 11:48:17 +08:00
parent 9618dd47ce
commit cc138adda9

View File

@@ -80,8 +80,9 @@ struct socket {
int64_t wb_size; int64_t wb_size;
int fd; int fd;
int id; int id;
uint16_t protocol; uint8_t protocol;
uint16_t type; uint8_t type;
uint16_t udpconnecting;
int64_t warn_size; int64_t warn_size;
union { union {
int size; int size;
@@ -262,6 +263,9 @@ reserve_id(struct socket_server *ss) {
if (s->type == SOCKET_TYPE_INVALID) { if (s->type == SOCKET_TYPE_INVALID) {
if (ATOM_CAS(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) { if (ATOM_CAS(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) {
s->id = id; s->id = id;
// socket_server_udp_connect may inc s->udpconncting directly (from other thread, before new_fd),
// so reset it to 0 here rather than in new_fd.
s->udpconnecting = 0;
s->fd = -1; s->fd = -1;
return id; return id;
} else { } else {
@@ -991,6 +995,7 @@ set_udp_address(struct socket_server *ss, struct request_setudp *request, struct
} else { } else {
memcpy(s->p.udp_address, request->address, 1+2+16); // 1 type, 2 port, 16 ipv6 memcpy(s->p.udp_address, request->address, 1+2+16); // 1 type, 2 port, 16 ipv6
} }
ATOM_DEC(&s->udpconnecting);
return -1; return -1;
} }
@@ -1399,7 +1404,7 @@ socket_server_connect(struct socket_server *ss, uintptr_t opaque, const char * a
static inline int static inline int
can_direct_write(struct socket *s, int id) { can_direct_write(struct socket *s, int id) {
return s->id == id && send_buffer_empty(s) && s->type == SOCKET_TYPE_CONNECTED && s->dw_buffer == NULL; return s->id == id && send_buffer_empty(s) && s->type == SOCKET_TYPE_CONNECTED && s->dw_buffer == NULL && s->udpconnecting == 0;
} }
// return -1 when error, 0 when success // return -1 when error, 0 when success
@@ -1417,7 +1422,14 @@ socket_server_send(struct socket_server *ss, int id, const void * buffer, int sz
// send directly // send directly
struct send_object so; struct send_object so;
send_object_init(ss, &so, (void *)buffer, sz); send_object_init(ss, &so, (void *)buffer, sz);
ssize_t n = write(s->fd, so.buffer, so.sz); ssize_t n;
if (s->protocol == PROTOCOL_TCP) {
n = write(s->fd, so.buffer, so.sz);
} else {
union sockaddr_all sa;
socklen_t sasz = udp_socket_address(s, s->p.udp_address, &sa);
n = sendto(s->fd, so.buffer, so.sz, 0, &sa.s, sasz);
}
if (n<0) { if (n<0) {
// ignore error, let socket thread try again // ignore error, let socket thread try again
n = 0; n = 0;
@@ -1435,9 +1447,8 @@ socket_server_send(struct socket_server *ss, int id, const void * buffer, int sz
sp_write(ss->event_fd, s->fd, s, true); sp_write(ss->event_fd, s->fd, s, true);
spinlock_unlock(&s->dw_lock); spinlock_unlock(&s->dw_lock);
return 0; return 0;
} else {
spinlock_unlock(&s->dw_lock);
} }
spinlock_unlock(&s->dw_lock);
} }
struct request_package request; struct request_package request;
@@ -1682,10 +1693,10 @@ socket_server_udp_send(struct socket_server *ss, int id, const struct socket_udp
so.free_func((void *)buffer); so.free_func((void *)buffer);
return 0; return 0;
} }
}
spinlock_unlock(&s->dw_lock); spinlock_unlock(&s->dw_lock);
// let socket thread try again, udp doesn't care the order // let socket thread try again, udp doesn't care the order
} }
}
struct request_package request; struct request_package request;
request.u.send_udp.send.id = id; request.u.send_udp.send.id = id;
@@ -1700,6 +1711,18 @@ socket_server_udp_send(struct socket_server *ss, int id, const struct socket_udp
int int
socket_server_udp_connect(struct socket_server *ss, int id, const char * addr, int port) { socket_server_udp_connect(struct socket_server *ss, int id, const char * addr, int port) {
struct socket * s = &ss->slot[HASH_ID(id)];
if (s->id != id || s->type == SOCKET_TYPE_INVALID) {
return -1;
}
spinlock_lock(&s->dw_lock);
if (s->id != id || s->type == SOCKET_TYPE_INVALID) {
spinlock_unlock(&s->dw_lock);
return -1;
}
ATOM_INC(&s->udpconnecting);
spinlock_unlock(&s->dw_lock);
int status; int status;
struct addrinfo ai_hints; struct addrinfo ai_hints;
struct addrinfo *ai_list = NULL; struct addrinfo *ai_list = NULL;