epoll behavior when writing to a file descriptor - epoll

I'm using epoll to write large messages to a server using HTTP protocol. The fds are all set to non-blocking and I'm using edge-triggered events. I know for EPOLLIN I need to loop over reading the fd until EAGAIN is returned. For writing I am unsure if I should keep looping once I get EAGAIN or should I wait for epoll to notify when the fd is available for read again.
For instance, I am writing a 20K message, and on the first ::write attempt the amount of data sent = 13K. The next attempt to write returns a retVal = -1 and errno = EAGAIN.
At this point should I continue looping in a while(1) until I can write the data or should I wait for epoll to invoke my call back when the FD is ready for writing again. My understanding is that since the fd is registered for writing, epoll should notify me when the FD is ready for writing again. But that doesn't seem to be happening in my program.
Do I need to set a special flag or modify the FD to get the notification?

At this point should I continue looping in a while(1) until I can write the data
No!
or should I wait for epoll to invoke my call back when the FD is ready for writing again.
Yes, you should (but what callback? epoll_wait doesn't have a callback mechanism, it just returns)
My understanding is that since the fd is registered for writing, epoll should notify me when the FD is ready for writing again. But that doesn't seem to be happening in my program.
If the FD is registered with EPOLLOUT or EPOLLIN | EPOLLOUT, it should indeed. Could you provide a small example demonstrating the problem?

Related

Question on the timing of re-arming EPOLL and related questions when using Epoll Edge Triggered

I have some questions on EPOLL when using Edge Triggered and with EPOLLONESHOT.
The simplified sequence of statements are listed below. Actually multiple files are monitored by an Epoll Fd and a set is managed through a specific thread. The variable names used speak for themselves and are, of course, set. That part is omitted for the sake of brevity:
1. Create epollFd
epollFd = epoll_create1(EPOLL_CLOEXEC);
2. Create events to monitor
epollEventParam.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP | EPOLLET | EPOLLONESHOT;
3. Add the FD to monitor and the events
epoll_ctl(epollFd, EPOLL_CTL_ADD, socketFd, &epollEventParam);
4. While loop with epoll_wait
while (1) {
noFdsEvented = epoll_wait(epollFd, epollEventsReported, maxEvents, -1);
/***************** REARM Here or after processing the events? ******/
epoll_ctl(epollFd, EPOLL_CTL_MOD, (int)epollEventsReported[i].data.fd, &epollEventParam);
/** if EPOLLIN, read until read returns EAGIN ***/
//Relevant code to read...
//After EAGAIN is returned, REARM Here instead of doing so earlier (above)?
/** if EPOLLOUT, write until write returns EAGIN ***/
//Relevant code to write...
//After EAGAIN is returned, REARM Here instead of doing so earlier (above)?
/*** If other events... process accordingly ***/
}
QUESTIONS:
When EPOLLONESHOT is used, when should EPOLL be REARMED? After the event is received or after the event is processed?
Elementary. When writing or reading, we keep track of the data point written/read until EAGAIN was returned or if partially read/written? Yes/No.
Initially EPOLLOUT is not set. When writing, when write returns EAGAIN, we add EPOLLOUT to the event
to be monitored. Yes/No?
When EPOLLOUT is triggered again for an FD, we continue writing from the point EAGAIN was last received
and do so until we get EAGAIN again. THen we REARM. Yes/No?
If we read partially and do not REARM, new data will continue to arrive but no event will be triggered.
So, if we read partially, we need to keep track of it and not rely only on the event handler to do read processing. Right?
I can't answer all of them, but I can try to answer a few.
Elementary. When writing or reading, we keep track of the data point written/read until EAGAIN was returned or if partially read/written? Yes/No.
For read/recv: you should handle all of the following scenarios
If you read/recv EAGAIN or EWOULDBLOCK. This indicates that there is nothing left to read/recv and you should break from the receive loop.
You receive 0 bytes. This indicates that the other side is no longer connected
You receive 0 > bytes. You successfully read/recv data and should read/recv again.
You dont necessarily need to keep track of the data as opposed to just ensure you handle the above 3 scenarios.
Initially EPOLLOUT is not set. When writing, when write returns EAGAIN, we add EPOLLOUT to the event to be monitored. Yes/No?
Yes...I believe that in the instance where EPOLLOUT is initially set, the same behaviour on the send() FD should occur as you described in the question...given that you will simply write to the FD regardless of the event notification and only stop once you get an EAGAIN/EWOULDBOCK error.

what's the exactly meaning of EV_TIMEOUT in libevent?

In Programming with Libevent book, it says:
EV_TIMEOUT
This flag indicates an event that becomes active after a timeout
elapses.
AFAIK, an event associate with socket fd will become active when network IO event is ready, which is notified by select/epoll/poll/kqueue.
If EV_TIMEOUT make an event active, while the socket fd is not ready, will event_base do the callback ?
Or the socket fd is ready, while EV_TIMEOUT is not, will event_base do the callback ?
Oh, I understand.
void (*event_callback_fn)(evutil_socket_t, short, void *);
The short flag will tell callback what happened exactly.
When timeout, short & EV_TIMEOUT == true, when socket is ready, short & (EV_READ | EV_WRITE) == true.

IOS: AsyncSocket - readData method's invoke mechanism

things are like this:
I used AsyncSocket to connect with server. when the server send some bytes to client at a time, app will invoke (onSocket: didReadData: withTag:) method; Sometimes, because of the network or other reason, some bytes arrived and the rest bytes arrived later( which means some bytes are delayed).(timeOut = -1)
==================================
Question: how much times did the method(onSocket: didReadData: withTag: ) invoke?
1)only one time - it will wait automatically until the bytes are complete?
2)2 or more times - some arrived(invoke), other arrived(invoke)、、、、、like so?
===================================
which thoughts is right? plz geiv me some advice. Thanks very much.
OK, maybe it's just like this.
Transfer data on TCP: when you send 1000 bytes at a time, because of lag or other reasons, you may receive the 900 bytes first, but the TCP socket will wait the rest 100 bytes
automatically. So if I use asyncSocket to transfer datas and set the timeout, during these seconds, I don't need to deal with the lagged data.
=========================
EDIT
maybe the title of ths question is not appropriate, no one cares the question.
I used the method -readDataToLength: instead, first read header.length of data, and parse it, then read the body.length of data;

How to send data immediately in epoll ET mode when connect established

My server needs to send data when client connects to it. I am using Epoll ET mode.
But how to do it? Could any one give me a simple example for me?
Assuming you are listening on your socket (socket, bind, listen), and have added it's descriptor to epoll (epoll_create and epoll_ctl), then epoll_wait will tell you when there is a new connection to accept.
First you accept the connection (sockfd is descriptor of socket you're listening on, efd is epoll instance) and add it to your epoll instance:
int connfd = accept4(sockfd, NULL, 0, SOCK_NONBLOCK);
struct epoll_event ev;
ev.events = EPOLLOUT | EPOLLET;
ev.data.fd = connfd;
epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &ev)
Then you go back to your main loop and call epoll_wait again. It will tell you when the socket is ready for writing, and you just happily write or sendfile away.
Add lots of error checking, and probably TCP_CORK and you're done. There's a working example on github.com/grahamking/netshare/.
I hope this gives you enough information to get started.

Resetting comm event mask

I have been doing overlapped serial port communication in Delphi lately and there is one problem I'm not sure how to solve.
I communicate with a modem. I write a request frame (an AT command) to the modem's COM port and then wait for the modem to respond. The event mask of the port is set to EV_RXCHAR, so when I write a request, I call WaitCommEvent() and start waiting for data to appear in the input queue. When overlapped waiting for event finishes, I immediately start reading data from the queue and read all that the device sends at once:
1) write a request
2) call WaitCommEvent() and wait until waiting finishes
3) read all the data that the device sends (not only the data being in the input queue at that moment)
4) do something and then goto 1
Waiting for event finishes after first byte appears in the input queue. During my read operation, however, more bytes appear in the queue and each of them causes an internal event flag to be set. This means that when I read all the data from the queue and then call WaitCommEvent() for the second time, it will immediately return with EV_RXCHAR mask, even though there is no data to be read.
How should I handle reading and waiting for event to be sure that the event mask returned by WaitCommEvent() is always valid? Is it possible to reset the flags of the serial port so that when I read all data from the queue and call WaitCommEvent() after then, it will not return immediately with a mask that was valid before I read the data?
The only solution that comes to my mind is this:
1) write a request
2) call WaitCommEvent() and wait until waiting finishes
3) read all the data that the device sends (not only the data being in the input queue at that moment)
4) call WaitCommEvent() which should return true immediately at the same time resetting the event flag set internally
5) do something and goto 1
Is it a good idea or is it stupid? Of course I know that the modem almost always finishes its answers with CRLF characters so I could set the comm mask to EV_RXFLAG and wait for the #10 character to appear, but there are many other devices with which I communicate and they do not always send frame end characters.
Your help will be appreciated. Thanks in advance!
Mariusz.
Your solution does sound workable. I just use a state machine to handle the transitions.
(psuedocode)
ioState := ioIdle;
while (ioState <> ioFinished) and (not aborted) do
Case ioState of
ioIdle : if there is data to read then set state to ioMidFrame
ioMidframe : if data to read then read, if end of frame set to ioEndFrame
ioEndFrame : process the data and set to ioFinished
ioFinished : // don't do anything, for doc purposes only.
end;

Resources