I am tryign to find out why my program is freezing and i narrowed it down to GetQueuedCompletionStatus().
All the IOCP threads are frozen and the only blocking call the threads have is GetQueuedCompletionStatus().
Is there any reason that GetQueuedCompletionStatus() would keep blocking forever after about 30mins~6hours of running time even thought there are still customers connected to the associated sockets?
This is a TCP Winsock program which uses IOCP.
The OS is Windows Server 2008 R2 Enterprise.
Thanks.
Thread code:
while (TRUE)
{
pClient = NULL;
pOverlapped = NULL;
bRet = GetQueuedCompletionStatus(hCompletionPort, &dwIOLen, (LPDWORD)&pClient, (LPOVERLAPPED*)&pOverlapped, INFINITE);
if (bRet == true && pClient != NULL && pOverlapped != NULL && pClient->bConnected == true && pClient->bToDisconnect == false)
{
if (pOverlapped->bIOMode == 0) // Recv
{
if (TryEnterCriticalSection(&pClient->mNetworkReadCSection))
{
pClient->dwSockBuffLength += dwIOLen;
// Packet processing here...
WSABUF pWSABuf;
pWSABuf.buf = (char*)&pClient->mSockBuffer[pClient->dwSockBuffLength];
pWSABuf.len = 10000 - pClient->dwSockBuffLength;
DWORD dwRecvd;
DWORD dwFlags = 0;
memset(&pClient->mSockOverlapped, 0x00, sizeof(WSAOVERLAPPED));
pClient->mSockOverlapped.bIOMode = 0;
int iSent = WSARecv(pClient->ClientSocket, &pWSABuf, 1, &dwRecvd, &dwFlags, (WSAOVERLAPPED*)&pClient->mSockOverlapped, NULL);
if (iSent == SOCKET_ERROR)
{
if (WSAGetLastError() == 10053 || WSAGetLastError() == 10054 || WSAGetLastError() == 10058)
{
//pClient->bToDisconnect = true;
//LeaveCriticalSection(&pClient->mNetworkReadCSection);
OnDissconnect(pPacketWriter, pClient->iClientID);
continue;
}
if (WSAGetLastError() != 997 && WSAGetLastError() != 10004 && WSAGetLastError() != 10038)
WriteToFile("IOCPSocketErr.txt", "[%s] Socket Error: %d\n", pClient->szPlayerName, WSAGetLastError());
}
LeaveCriticalSection(&pClient->mNetworkReadCSection);
}
else
{
PostQueuedCompletionStatus(hCompletionPort, dwIOLen, (DWORD)pClient, (OVERLAPPED*)pOverlapped);
}
}
else if (pOverlapped->bIOMode == 1) // Send
{
dwBytesSent += dwIOLen;
}
}
}
It's most likely a bug in your code.
I've been working with IOCP and GetQueuedCompletionStatus() for over 10 years now and I've never seen an issue with it on any platform.
For a start, the commented out LeaveCriticalSection(&pClient->mNetworkReadCSection); above the disconnect will leave your socket locked after this error...
Personally I prefer to see the error constants used rather than magic numbers, it's hard for me to see exactly which errors you are 'handling' here.
I expect that you're ending up in a situation where you have no I/O operations pending, and so you have no activity on your IOCP threads. You could maintain a counter for debug purposes which you increment when you issue an I/O operation and decrement when it completes, also increment it when you post your own completions to the port. This would then help you see if you have any I/O operations pending when you break into your hung program. Remember to increment the counter BEFORE you issue the operation (and decrement it if the operation failed) rather than issuing it after as otherwise the counter may go negative if the completion occurs before the increment.
If I read the documentation correctly you can have a case where GetQueuedCompletionStatus returns false and pOverlapped is not NULL. Perhaps you should test for and handle this case.
Related
I am writing a cross-platform socket handling library (which also handles serial and a whole bunch of other protocols in a protocol agnostic way. - I am not re-inventing the wheel).
I need to emulate the Linux poll function. The code I started with used select and worked fine, but there was no way to interrupt it from another thread, and so I was forced to start using event objects. My initial attempt called:
WSACreateEvent()
WSAEventSelect() to associate the socket with the event object.
WaitForMultipleObjectsEx() to wait on all sockets plus my interrupt event object.
select() to work out what events actually occurred on the socket.
accept()/send()/recv() to process the sockets (later and elsewhere).
This failed. accept() was claiming that the file descriptor was not a socket. If I commented out the call to WSAEventSelect(), essentially reverting to my earlier code, it all works fine (except that I cannot interrupt).
I then realised that I did something wrong (according to the Microsoft dictatorship). Instead of using select() to work out what events have happened on each socket, I should be using WSAEnumNetworkEvents(). So I rewrote my code to do it the proper way, remembering to call WSAEventSelect() afterwards to disassociate the event object from the file descriptor so that (fingers crossed) accept() would now work.
Now WSAEnumNetworkEvents() is returning an error and WSAGetLastError() tells me that the error is WSAENOTSOCK.
This IS a socket. I am doing things the way MSDN tells me I should (allowing for the general poor quality of the documentation). It appears however that WSAEventSelect() is causing the file descriptor to be marked as a file rather than a socket.
I hate Microsoft so much right now.
Here is a cut down version of my code:
bool do_poll(std::vector<struct pollfd> &poll_data, int timeout)
{
...
for (const auto &fd_data : poll_data) {
event_mask = 0;
if (0 != (fd_data.events & POLLIN)) {
// select() will mark a socket as readable when it closes (read size = 0) or (for
// a listen socket) when there is an incoming connection. This is the *nix paradigm.
// WSAEventSelect() hasseparate events.
event_mask |= FD_READ;
event_mask |= FD_ACCEPT;
event_mask |= FD_CLOSE;
}
if (0 != (fd_data.events & POLLOUT)) {
event_mask |= FD_WRITE;
}
event_obj = WSACreateEvent();
events.push_back(event_obj);
if (WSA_INVALID_EVENT != event_obj) {
(void)WSAEventSelect((SOCKET)fd_data.fd, event_obj, event_mask);
}
}
lock.lock();
if (WSA_INVALID_EVENT == interrupt_obj) {
interrupt_obj = WSACreateEvent();
}
if (WSA_INVALID_EVENT != interrupt_obj) {
events.push_back(interrupt_obj);
}
lock.unlock();
...
(void)WaitForMultipleObjectsEx(events.size(), &(events[0]), FALSE, dw_timeout, TRUE);
for (i = 0u; i < poll_data.size(); i++) {
if (WSA_INVALID_EVENT == events[i]) {
poll_data[i].revents |= POLLERR;
} else {
if (0 != WSAEnumNetworkEvents((SOCKET)(poll_data[i].fd), events[i], &revents)) {
poll_data[i].revents |= POLLERR;
} else {
if (0u != (revents.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))) {
poll_data[i].revents |= POLLIN;
}
if (0u != (revents.lNetworkEvents & FD_WRITE)) {
poll_data[i].revents |= POLLOUT;
}
}
(void)WSAEventSelect((SOCKET)(poll_data[i].fd), NULL, 0);
(void)WSACloseEvent(event_obj);
}
}
...
}
I have a server written in plain-old C accepting TCP connections using kqueue on FreeBSD.
Incoming connections are accepted and added to a simple connection pool to keep track of the file handle.
When data is received (on EVFILT_READ), I call recv() and then I put the payload in a message queue for a different thread to process it.
Receiving and processing data this way works perfect.
When the processing thread is done, it may need to send something back to the client. Since the processing thread has access to the connection pool and can easily get the file handle, I'm simply calling send() from the processing thread.
This works 99% of the time, but every now and then kqueue gives me a EV_EOF flag, and the connection is dropped.
There is a clear correlation between the frequency of the calls to send() and the number of EV_EOF errors, so I have a feeling the EV_EOF due to some race condition between my kqueue thread and the processing thread.
The calls to send() always returns the expected byte count, so I'm not filling up the tx buffer.
So my question; Is it acceptable to call send() from a separate thread as described here? If not, what would be the right way to send data back to the clients asynchronously?
All the examples I find calls send() in the same context as the kqueue loop, but my processing threads may need to send back data at any time - even minutes after the last received data from the client - so obviously I can't block the kqueue loop for that time..
Relevant code snippets:
void *tcp_srvthread(void *arg)
{
[[...Bunch of declarations...]]
tcp_serversocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
...
setsockopt(tcp_serversocket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(int));
...
err = bind(tcp_serversocket, (const struct sockaddr*)&sa, sizeof(sa));
...
err = listen(tcp_serversocket, 10);
...
kq = kqueue();
EV_SET(&evSet, tcp_serversocket, EVFILT_READ | EV_CLEAR, EV_ADD, 0, 0, NULL);
...
while(!fTerminated) {
timeout.tv_sec = 2; timeout.tv_nsec = 0;
nev = kevent(kq, &evSet, 0, evList, NLIST, &timeout);
for (i=0; i<nev; i++) {
if (evList[i].ident == tcp_serversocket) { // new connection?
socklen = sizeof(addr);
fd = accept(evList[i].ident, &addr, &socklen); // accept it
if(fd > 0) { // accept ok?
uidx = conn_add(fd, (struct sockaddr_in *)&addr); // Add it to connected controllers
if(uidx >= 0) { // add ok?
EV_SET(&evSet, fd, EVFILT_READ | EV_CLEAR, EV_ADD, 0, 0, (void*)(uint64_t)(0x00E20000 | uidx)); // monitor events from it
if (kevent(kq, &evSet, 1, NULL, 0, NULL) == -1) { // monitor ok?
conn_delete(uidx); // ..no, so delete it from my list also
}
} else { // no room on server?
close(fd);
}
}
else Log(0, "ERR: accept fd=%d", fd);
}
else
if (evList[i].flags & EV_EOF) {
[[ ** THIS IS CALLED SOMETIMES AFTER CALLING SEND - WHY?? ** ]]
uidx = (uint32_t)evList[i].udata;
conn_delete( uidx );
}
else
if (evList[i].filter == EVFILT_READ) {
if((nr = recv(evList[i].ident, buf, sizeof(buf)-2, 0)) > 0) {
uidx = (uint32_t)evList[i].udata;
recv_data(uidx, buf, nr); // This will queue the message for the processing thread
}
}
}
else {
// should not get here.
}
}
}
The processing thread looks something like this (obviously there's a lot of data manipulation going on in addition to what's shown) :
void *parsethread(void *arg)
{
int len;
tmsg_Queue mq;
char is_ok;
while(!fTerminated) {
if((len = msgrcv(msgRxQ, &mq, sizeof(tmsg_Queue), 0, 0)) > 0) {
if( process_message(mq) ) {
[[ processing will find the uidx of the client and build the return data ]]
send( ctl[uidx].fd, replydata, replydataLen, 0 );
}
}
}
}
Appreciate any ideas or nudges in the right direction. Thanks.
EV_EOF
If you write to a socket after the peer closed the reading part of it, you will receive a RST, which triggered EVFILT_READ with EV_EOF set.
Async
You should try aio_read and aio_write.
I have a server that receives commands from various other local processes.
I chose the most simplest form (endless loop with accept-read), but here the socket-connections remain open and I soon run out of them (running on a virtual host). Then, on a client, socket() fails with the error message "Cannot allocate memory". (However memory is not the problem, it surely is some socket-limitation from the virtual host.)
I also tried to have the whole thing (unlink-socket-bind-accept-listen-read-close) in an endless loop, which also does not solve the problem. One of these commands seems to grab a socket-connection that never gets released. (Only killing and restarting the server process allows the clients to connect again) Using shutdown() before close() also does not help.
The type of the socket is AF_UNIX / SOCK_SEQPACKET.
How can I use a socket without leaking system ressources?
Edit: As requested the endless loop in the server:
while(1)
{
unlink(SOCKET_FILE_PATH);
if((socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0)
{
perror("socket() failed");
return 1;
}
if(bind(socket_fd, (const struct sockaddr *) &server_address, sizeof(server_address)) < 0)
{
close(socket_fd);
perror("bind() failed");
return 1;
}
listen(socket_fd, 10);
newsockfd = accept(socket_fd, (struct sockaddr *)&cli_addr, &clilen);
if (newsockfd < 0)
{
perror("ERROR on accept");
return 1;
}
bzero(buffer,256);
n = read( newsockfd,buffer,255 );
if (n < 0)
{
perror("ERROR reading from socket");
return 1;
}
printf("buffer: \"%s\"\n",buffer);
shutdown(socket_fd, SHUT_RDWR);
close(socket_fd);
}
Where do you close 'newsockfd'? Also, there is no guarantee that the buffer contains a null-terminated string, so calling printf(%s..) on it will likely segfault or some other UB.
Hello there I am getting mad with this issue since I'm using a simple pattern.
Ok, I have a infinite while in which I use epoll_wait on server socket and already connected sockets. All went ok if a new socket send a connection request; my problem is when connected sockets (right now I am just using one socket sending 390k packet) sends data: doesn't matter if I use EPOLLONESHOT or EPOLLET, after consumed all request buffer on that socket, rearming socket or receiving EAGAIN on recv(), epoll_wait always wakes up again with wrong buffer!
My server works with threadpool, but right now is just one thread that does all work (to simplify testing):
while (TRUE) {
int num = epoll_wait(efd, events, MAX_EVENTS, -1);
for (int i = 0; i < num; i++) { // ciclo epoll()
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP || !(events[i].events & EPOLLIN)) {
fprintf (stderr, "epoll error on socket: closed\n");
s = epoll_ctl(efd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
}
else if (events[i].data.fd == serverSocket) {
while (TRUE) {
newInfoClient = server->m_bgServer->AcceptClient(&newSocketClient);
if (newInfoClient == NULL) { // nessun client
break;
}
else {
printf("\nSocket accettato: %d", newSocketClient);
s = CSocket::MakeNonBlocking(newSocketClient);
if (s == -1)
abort();
event.data.fd = newSocketClient;
event.events = EPOLLIN | EPOLLET;
s = epoll_ctl(efd, EPOLL_CTL_ADD, newSocketClient, &event);
if (s == -1) {
abort();
}
}
}
else {
AbstractTcpServerGame::DownloadTcpRequest(client);
}
}
}
I have just omitted some checks and other internal codes.
AbstractTcpServerGame::DownloadTcpRequest(...)
This function is just a recv in loop to rescues my own header, get buffer body and just to verify empty buffer outside loop I call a simple recv() that returns -1 (errno=EAGAIN or EWOULDBLOCK).
After this when I rearm the socket with epoll_ctr() in DownloadTcpRequest() in EPOLLONESHOT case, when it returns epoll_wait() wakes up again on the same socket!! this is my execution log:
New socket (6) request (errno 11) <--- when epoll_wait() emits EPOLLIN on socket 6
Download of 18 bytes (socket 6) <-- inside AbstractTcpServerGame::DownloadTcpRequest()
Download of 380k (socket 6) <-- another recv() loop to rescue body request
------------------- empty buffer on socket 6 ----------- <-- dummy recv to show empty buffer
New socket (6) request (errno 11)
Download of 18 bytes (socket 6)
Download of -1556256155 (socket 6)
Error on socket 6 (bad::alloc exception)
Client sends 398k (18 header + body) and all data are correctly received as shown above, but rearming socket or using EPOLLET, epoll_wait() generates another request and I don't know where those are taken infact are not correct!
I use sockets in non-blocking mode, and sometimes WSAConnect function returns WSAEINVAL error.
I investigate a problem and found, that it occurs if there is no pause (or it is very small ) between
WSAConnect function calls.
Does anyone know how to avoid this situation?
Below you can found source code, that reproduce the problem. If I increase value of parameter in Sleep function to 50 or great - problem dissapear.
P.S. This problem reproduces only on Windows XP, on Win7 it works well.
#undef UNICODE
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")
static int getError(SOCKET sock)
{
DWORD error = WSAGetLastError();
return error;
}
void main()
{
SOCKET sock;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
fprintf(stderr, "Socket Initialization Error. Program aborted\n");
return;
}
for (int i = 0; i < 1000; ++i) {
struct addrinfo hints;
struct addrinfo *res = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
hints.ai_protocol = IPPROTO_TCP;
if (0 != getaddrinfo("172.20.1.59", "8091", &hints, &res)) {
fprintf(stderr, "GetAddrInfo Error. Program aborted\n");
closesocket(sock);
WSACleanup();
return;
}
struct addrinfo *ptr = 0;
for (ptr=res; ptr != NULL ;ptr=ptr->ai_next) {
sock = WSASocket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol, NULL, 0, NULL); //
if (sock == INVALID_SOCKET)
int err = getError(sock);
else {
u_long noblock = 1;
if (ioctlsocket(sock, FIONBIO, &noblock) == SOCKET_ERROR) {
int err = getError(sock);
closesocket(sock);
sock = INVALID_SOCKET;
}
break;
}
}
int ret;
do {
ret = WSAConnect(sock, ptr->ai_addr, (int)ptr->ai_addrlen, NULL, NULL, NULL, NULL);
if (ret == SOCKET_ERROR) {
int error = getError(sock);
if (error == WSAEWOULDBLOCK) {
Sleep(5);
continue;
}
else if (error == WSAEISCONN) {
fprintf(stderr, "+");
closesocket(sock);
sock = SOCKET_ERROR;
break;
}
else if (error == 10037) {
fprintf(stderr, "-");
closesocket(sock);
sock = SOCKET_ERROR;
break;
}
else {
fprintf(stderr, "Connect Error. [%d]\n", error);
closesocket(sock);
sock = SOCKET_ERROR;
break;
}
}
else {
int one = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one));
fprintf(stderr, "OK\n");
break;
}
}
while (1);
}
std::cout<<"end";
char ch;
std::cin >> ch;
}
You've got a whole basketful of errors and questionable design and coding decisions here. I'm going to have to break them up into two groups:
Outright Errors
I expect if you fix all of the items in this section, your symptom will disappear, but I wouldn't want to speculate about which one is the critical fix:
Calling connect() in a loop on a single socket is simply wrong.
If you mean to establish a connection, drop it, and reestablish it 1000 times, you need to call closesocket() at the end of each loop, then call socket() again to get a fresh socket. You can't keep re-connecting the same socket. Think of it like a power plug: if you want to plug it in twice, you have to unplug (closesocket()) between times.
If instead you mean to establish 1000 simultaneous connections, you need to allocate a new socket with socket() on each iteration, connect() it, then go back around again to get another socket. It's basically the same loop as for the previous case, except without the closesocket() call.
Beware that since XP is a client version of Windows, it's not optimized for handling thousands of simultaneous sockets.
Calling connect() again is not the correct response to WSAEWOULDBLOCK:
if (error == WSAEWOULDBLOCK) {
Sleep(5);
continue; /// WRONG!
}
That continue code effectively commits the same error as above, but worse, if you only fix the previous error and leave this, this usage will then make your code start leaking sockets.
WSAEWOULDBLOCK is not an error. All it means after a connect() on a nonblcoking socket is that the connection didn't get established immediately. The stack will notify your program when it does.
You get that notification by calling one of select(), WSAEventSelect(), or WSAAsyncSelect(). If you use select(), the socket will be marked writable when the connection gets established. With the other two, you will get an FD_CONNECT event when the connection gets established.
Which of these three APIs to call depends on why you want nonblocking sockets in the first place, and what the rest of the program will look like. What I see so far doesn't need nonblocking sockets at all, but I suppose you have some future plan that will inform your decision. I've written an article, Which I/O Strategy Should I Use (part of the Winsock Programmers' FAQ) which will help you decide which of these options to use; it may instead guide you to another option entirely.
You shouldn't use AI_PASSIVE and connect() on the same socket. Your use of AI_PASSIVE with getaddrinfo() tells the stack you intend to use this socket to accept incoming connections. Then you go and use that socket to make an outgoing connection.
You've basically lied to the stack here. Computers find ways to get revenge when you lie to them.
Sleep() is never the right way to fix problems with Winsock. There are built-in delays within the stack that your program can see, such as TIME_WAIT and the Nagle algorithm, but Sleep() is not the right way to cope with these, either.
Questionable Coding/Design Decisions
This section is for things I don't expect to make your symptom go away, but you should consider fixing them anyway:
The main reason to use getaddrinfo() — as opposed to older, simpler functions like inet_addr() — is if you have to support IPv6. That kind of conflicts with your wish to support XP, since XP's IPv6 stack wasn't nearly as heavily tested during the time XP was the current version of Windows as its IPv4 stack. I would expect XP's IPv6 stack to still have bugs as a result, even if you've got all the patches installed.
If you don't really need IPv6 support, doing it the old way might make your symptoms disappear. You might end up needing an IPv4-only build for XP.
This code:
for (int i = 0; i < 1000; ++i) {
// ...
if (0 != getaddrinfo("172.20.1.59", "8091", &hints, &res)) {
...is inefficient. There is no reason you need to keep reinitializing res on each loop.
Even if there is some reason I'm not seeing, you're leaking memory by not calling freeaddrinfo() on res.
You should initialize this data structure once before you enter the loop, then reuse it on each iteration.
else if (error == 10037) {
Why aren't you using WSAEALREADY here?
You don't need to use WSAConnect() here. You're using the 3-argument subset that Winsock shares with BSD sockets. You might as well use connect() here instead.
There's no sense making your code any more complex than it has to be.
Why aren't you using a switch statement for this?
if (error == WSAEWOULDBLOCK) {
// ...
}
else if (error == WSAEISCONN) {
// ...
}
// etc.
You shouldn't disable the Nagle algorithm:
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ...);