EINTR and epoll_ctl, should I check errno? - c

I am looking through code for FreeBSD. The code uses kevent programming interface. Now, I find the lines like below:
status = kevent(...)
if(status < 0){
if(EINTR == errno){
goto l_kevent;
}
/* ... */
}
I need to port the code for Linux, and I wonder... Should I check for EINTR with Linux epoll calls. I know that epoll has epoll_pwait, and it is still should be checked for EINTR. But the documentation I have on hand tells me nothing about the epoll_ctl calls being interruptible.
I can look into source code for epoll. But, as humble, as I am, I do not know how signals are handled in kernel. So, if the code itself relies on some interrupt mechanics, I do not know where to look for return codes of interest.
Hope I explained problem. The question, once again: my documentation tell me nothing on epoll_ctl being interruptible, what should I do? Should I check for EINTR?
P.S
If someone will point me out for the source code for the epoll, that I can comprehend, I will gladly try to do my own research.

Related

Is it possible to do epoll on accept event?

Let's suppose I've created a listening socket:
sock = socket(...);
bind(sock,...);
listen(sock, ...);
Is it possible to do epoll_wait on sock to wait for incoming connection? And how do I get client's socket fd after that?
The thing is on the platform I'm writing for sockets cannot be non-blocking, but there is working epoll implementation with timeouts, and I need to accept connection and work with it in a single thread so that it doesn't hang if something goes wrong and connection doesn't come.
Without knowing what this non-standard platform is it's impossible to know exactly what semantics they gave their epoll call. But on the standard epoll on Linux, a listening socket will be reported as "readable" when an incoming connection arrives, and then you can accept the connection by calling accept. If you leave the socket in blocking mode, and always check for readability using epoll's level-triggered mode before each call to accept, then this should work – the only risk is that if you somehow end up calling accept when no connection has arrived, then you'll get stuck. For example, this could happen if there are two processes sharing a listening socket, and they both try to accept the same connection. Or maybe it could happen if an incoming connection arrives, and then is closed again before you call accept. (Pretty sure in this case Linux still lets the accept succeed, but this kind of edge case is exactly where I'd be suspicious of a weird platform doing something weird.) You'd want to check these things.
Non-blocking mode is much more reliable because in the worst case, accept just reports that there's nothing to accept. But if that's not available, then you might be able to get away with something like this...
Since this answer is the first up in the results in duckduckgo. I will just chime in to say that under GNU/Linux 4.18.0-18-generic (Ubuntu 18.10).
The asynchronously accept an incoming connection using one has to watch for errno value EWOULDBLOCK (11) and then add the socket to epoll read set.
Here is a small shot of scheme code that achieves that:
(define (accept fd)
(let ((out (socket:%accept fd 0 0)))
(if (= out -1)
(let ((code (socket:errno)))
(if (= code EWOULDBLOCK)
(begin
(abort-to-prompt fd 'read)
(accept fd))
(error 'accept (socket:strerror code))))
out)))
In the above (abort-to-prompt fd 'read) will pause the coroutine and add fd to epoll read set, done as follow:
(epoll-ctl epoll EPOLL-CTL-ADD fd (make-epoll-event-in fd)))
When the coroutine is unpaused, the code proceed after the abort to call itself recursively (in tail-call position)
In the code I am working in Scheme, it is a bit more involving since I rely on call/cc to avoid callbacks. The full code is at source hut.
That is all.

Can socket() fail with EINPROGRESS

Is it possible for the socket() function to fail with EINPROGRESS in Linux? Note that I am specifically asking about socket(), not connect() or others.
POSIX does not list EINPROGRESS as a possible error code. However the manpage for socket() in Linux says:
Other errors may be generated by the underlying protocol modules.
Is there any circumstances in which this call can actually fail with EINPROGRESS?
EINPROGRESS means the operation is now in progress. It would block because of an external reason : wait for a remote action or a local device.
socket() is only creating an entry in the memory of the system : there is no reason to wait for any remote action or any device.
But if it were able to return EINPROGRESS, you would have nothing to wait for.
With file handles and socket handles, you can use select() in order to wait for the system to be ready. But if the socket() itself does not return anything, you have nothing to wait on.
I see no reason for socket() to return EIPROGRESS but it would be a bad idea anyway.
Maybe not the answer you were looking for:
You'll have to check the corresponding Linux kernel source code (kernel/net/socket.c) throughly to be 100% sure. Glancing through the code, it doesn't look like EINPROGRESS is returned anywhere. However, there are runtime dependent calls in there, so its difficult to say just from static code analysis.

Installing signal handlers for variables that are defined in a header file in C

So I am working on this code for a class and I have little experience with signal handlers. I have 95% of my code done, however, I am struggling with this bit.
This is what the professor is asking for on this assignment.
Then, main() should install 4 signal handler:
The handler for TIME_OVER_SIGNAL announces that the time is up and sets shouldRun to 0.
The handler for WIN_SIGNAL announces that the user won and sets shouldRun to 0.
The handler for CORRECT_SIGNAL announces that the user got their last guess correct.
The handler for INCORRECT_SIGNAL announces that the user got their last guess wrong, and should start again from the beginning.
NOTE: Perhaps you can make the same handler handle both CORRECT_SIGNAL and INCORRECT_SIGNAL.
I haven't been successful finding any examples online similar to this to steer me in the right direction of what to do.
This is what I basically got out of the explanation and I know for a fact it's probably way off the mark... How do I go about installing these so they output a particular message like is being asked? The only examples I can find online are for generic alarms, sigChld, or to be able to Ctrl^C out of a running program.
void timeOverSignalHandler(int sigINT)
{
printf("Oh no! The time is up!");
shouldRun = 0;
}
I'm confused what arguments should be passed. I'm also confused whether or not I should be doing something different within the handler and when I call the handler within the main I should have the output generate there.
If anybody could be kind enough to guide me in the right direction with this one I would greatly appreciate your help! Any sort of example that would be similar to this would be great, where the handler is used to output a specific phrase to the user. Doesn't have to necessarily be these particular handlers that I need to do for the assignment. This is a C program!
Not really sure what your aim is but signals according to GNU:
A signal is a software interrupt delivered to a process. The operating system uses signals to report exceptional situations to an executing program. Some signals report errors such as references to invalid memory addresses; others report asynchronous events, such as disconnection of a phone line.
If you have a 64 bit OS you should be able to use SIGNUM's from 1 to 64, notice some of this include already managed signals like SIGTERM.
The following code manages and raises signal 10(SIGUSR1), that I defined with one of your ID's:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#define TIME_OVER_SIGNAL 28
static void catInteractive attention sch_function(int signo) {
puts("Signal caught.");
}
int main(void) {
if (signal(TIME_OVER_SIGNAL, catch_function) == SIG_ERR) {
fputs("An error occurred while setting a signal handler.\n", stderr);
return EXIT_FAILURE;
}
puts("Raising the interactive attention signal.");
if (raise(TIME_OVER_SIGNAL) != 0) {
fputs("Error raising the signal.\n", stderr);
return EXIT_FAILURE;
}
puts("Exiting.");
return EXIT_SUCCESS;
}

Slow system call and signals

I have read this subject:
Relationship slow system call with signal
and everything isn't clear for me. Especially I don't understand this part of answer because I don't see a problem with included source code.
Please explain me.
Thanks in advance.
Anyway, back to the question. If you're wondering why the read doesn't
fail with EINTR the answer is SA_RESTART. On most Unix systems a few
system calls are automatically restarted in the event of a signal.
The OP was expecting the read call to return an error code because it was interrupted by a signal. In the case of the read system call, the OS automatically restarts this system call in the event of a signal, so no error was returned.

Posix evtsuspend equivalent

I am migrating a LynxOS program to an ubuntu distribution and gcc 4.1.3
I am almost done but I have a problem, I am receiving SIGALRM signal which forces my program to exit. I dont know why I am receiving this signals if I am not calling to alarm(x).
I roundabouted this with a sigaction, but my program is not working properly mq_receive is failing every time this SIGALRM is received.
I wonder if it could be because of this code translation:
#include <events.h>
#include <timers.h>
evtset_t EvtMask;
struct timespec Time;
Time.tv_sec = 2;
Time.tv_nsec = 0;
evtsuspend (&EvtMask, &Time);
would now be
sleep(2);
This is the info about evtsuspend given by LynxOS:
evtsuspend
(cant insert the image because of my lack of reputation)
Do you think they work the same? (without specifying an event mask) sleep() also waits for a SIGALRM to continue.
Thanks and regards
1) Try running strace on your program to see if you can find out more info.
It'd be nice to have more details about your program... but maybe this will help.
Maybe mq_receive() is timing out. I think that SIGALRM is used to notify applications for timed-out system calls.
Or more likely, you're using something else that's causing SIGALRM in your code, ie: setitimer().
As for your question about using sleep(2) on linux. If you want the program to block during the sleep(2) call, then yes you should be OK with using it. If you don't want it to block, then start an interval timer setitimer() and use that. Note: setitimer() uses SIGALRM when the timer fires... see the manpage for details.
I see this is an old topic, but here is an answer to the mq_receive() part of your question:
mq_receive() will unblock when a signal is received. When this happens, the return code will be set to -1 and errno will be set to EINTR. You can wrap code around your call to mq_receive() to check for this and recall it if necessary.

Resources