Re: Function: int recv (Socket, Buffer,Length, Flags) is returning with the error number 4



Rainer Weikusat <rweikusat@xxxxxxxxxxx> writes:
scott@xxxxxxxxxxxxx (Scott Lurndal) writes:
Rainer Weikusat <rweikusat@xxxxxxxxxxx> writes:
Barry Margolin <barmar@xxxxxxxxxxxx> writes:
In article <5g5vu7F3ef7jtU1@xxxxxxxxxxxxxxxxx>,
Ulrich Eckhardt <doomster@xxxxxxxx> wrote:
monty wrote:
I am facing a problem when a call made to the socket function recv. It
is returning with the error number 4(EINTR).
When I further analyzed i came to know it is because of the "A signal
interrupted the recv subroutine before any data was available ".

If I remember correctly, this just means that while the system call was
under way, your program received (and possibly handled) a signal and
therefore the syscall was aborted without anything being done. Just retry
the recv() and you should be fine.

I'd be interested in the rationale to behave like that, i.e. why EINTR is
provided/used at all, in this context or others.

Because the Unix designers didn't want to preserve the kernel state of
an in-progress system call while going back to user mode to invoke the
signal handler.

That's a nice speculation by someone with little clue in kernel
programming. The first thing to note here is that not all system calls

May want to lay off the insults when you have really no clue about
Barry's prior computing experience.

I was refering to the indirect 'worse is better'-quote. The reason
(some) UNIX(*) system calls are interruptible is because there could
be a reason to interrupt them. One would assume this to be even more
true on early UNIX(*), before 'synchronous I/O multiplexing' was
invented.

Don't try to teach your grandma to suck eggs, sonny.


A characteristic of earlier Unix systems is that if a process
caught a signal while the process was blocked in a "slow"
system call, the system call was interrupted. The system call
returned an error and errno was set to EINTR. This was done
under the assumption that since a signal occurred and the
process caught it, there is a good chance that something has
happened that should wake up the blocked system call.
[APUE, 1st ed., p. 275]

Read some kernel code, not APUE, whatever that may be. Consider specifically
what it means from a kernel coding standpoint to "interrupt a system call".



[...]

If the system call returns with errno
set to EINTR after the handler was run, there was no 'kernel state' to
restore, because the process was blocked waiting for something[***].

This is clearly incorrect, since the modifications to the struct proc
(et alia) in order to 'block waiting for something' are precisely the
state changes that Barry was referring to.

To return to user space, the process has to return to user
space.

Note that signals are always delivered at the tail-end of the system
call process (just prior to returning to the application),

My comment was specifically in the context of an interrupted system call. The
kernel can deliver signals at any time to a thread which is currently
executing in user mode (ring 3 on x86, x86_64).


#include <signal.h>
#include <stdio.h>

static void handler(int unused)
{
puts("something stopped me");
exit(0);
}

int main(void)
{
signal(SIGALRM, handler);
alarm(3);
while (1);
return 0;
}

It follows that this program can never stop, because the SIGALRM
cannot be delivered. It stops, though, at least on Linux 2.6.

thus to deliver a signal prior to completion of the system call
(e.g. on an indefinite wait), one must roll-back the kernel state to
that at the time of the system call.

An example of the opposite (that I happen to have written ;-):

static int wcomplete_wait(struct file *file)
{
wait_queue_t wait;
volatile struct usblp *usblp;
int have_signal, complete, rc;

usblp = file->private_data;

if (!usblp_wcomplete((void *)usblp)) {
if (file->f_flags & O_NONBLOCK) return -EAGAIN;

init_waitqueue_entry(&wait, current);
add_wait_queue((wait_queue_head_t *)&usblp->wait, &wait);

goto check_status;
do {
schedule();

check_status:
set_current_state(TASK_INTERRUPTIBLE);
have_signal = signal_pending(current);
complete = usblp_wcomplete((void *)usblp);
} while (!(complete || have_signal));

set_current_state(TASK_RUNNING);
remove_wait_queue((wait_queue_head_t *)&usblp->wait, &wait);

if (!complete) return -EINTR;
}

rc = usblp->writeurb->status;
return rc;
}
[Linux 2.4 USB printer driver 'with some modifications', caller is
write/ writev]

For a blocking write, this is called after the URB (USB request
buffer) has been submitted to the host controller for transmission.
There isn't even a theoretical possibility of 'rolling this back' (see
OHCI spec).

So you complete it, wait for it, or cancel it.

scott
.



Relevant Pages

  • Re: Interrupt context...
    ... > gone through most of the posts on interrupt in usenet. ... > kernel stack and ISR is executed. ... More may be saved depending on the architecture. ... Here the kernel have assembler code to save all general ...
    (comp.os.linux.development.system)
  • Re: how do threads work?
    ... >> A process cannot consider to switch task unless the flow of instructions ... >> kernel for a little help, in the form of regular timer signals. ... If you now ask, how does the kernel deliver signals, then we are no longer ...
    (comp.os.linux.development.system)
  • Re: [PATCH 19-rc1] Fix typos in /Documentation : Misc
    ... +do not have a corresponding kernel virtual address space mapping) and ... This command sets the scale factor for the ABSOLUTE MOUSE POSITIONING mode. ... If you check the source code you will see that what I draw here as a frame ... interrupt-parent: contains the phandle of the interrupt ...
    (Linux-Kernel)
  • Re: [PATCH 18-rc3] Fix typos in /Documentation : Q-R
    ... The driver will receive them again on the ... The kernel is entered with r3 pointing to an area of memory that is ... Bits are then right shifted into the GP_SAMPLE register at the specified ... you get an interrupt when a full DWORD is recieved. ...
    (Linux-Kernel)
  • PROBLEM: oops in 2.6.21.1 after bringing up the network
    ... I am consistently getting a kernel oops from a vanilla 2.6.21.1 kernel. ... Fatal exception in interrupt ... pin B routed to IRQ 0 ... Elitegroup Computer Systems Unknown device b732 ...
    (Linux-Kernel)