struct siginfo {
int si_signo; /* signal number */
int si_errno; /* if nonzero, errno value from <errno.h> */
int si_code; /* additional info (depends on signal) */
pid_t si_pid; /* sending process ID */
uid_t si_uid; /* sending process real user ID */
void *si_addr; /* address that caused the fault */
int si_status; /* exit value or signal number */
long si_band; /* band number for SIGPOLL */
/* possibly other fields also */
};
I do not understand si_band.
If you look at the Linux manpage for sigaction, you'll see that:
SIGPOLL/SIGIO fills in si_band and si_fd. The si_band event is a bit mask
containing the same values as are filled in the revents field by poll(2).
The si_fd field indicates the file descriptor for which the I/O event
occurred.
The explanation for what that bitmask means can be found in the linked man page - essentially, it tells the signal handler what type of event triggered the signal (and in Linux at least, you also get the corresponding file descriptor.)
I'm not sure how portable this is. si_band seems to be in POSIX, but not si_fd. Reference: POSIX <signal.h>, POSIX poll(2)
A process can ask for SIGPOLL signals in order to implement asynchronous I/O. From the man page of sigactions:
SIGPOLL/SIGIO fills in si_band and si_fd. The si_band event is a
bit mask containing the same values as are filled in the revents field
by poll(2).
revents describes the types of the events that happened and lead to SIGPOLL being sent. The man page of poll, describes it in detail:
The field revents is an output parameter, filled by the kernel with
the events that actually occurred. The bits returned in revents can
include:
POLLIN There is data to read.
POLLPRI
There is urgent data to read (e.g., out-of-band data on TCP
socket; pseudoterminal master in packet mode has seen state
change in slave).
POLLOUT
Writing now will not block.
POLLRDHUP (since Linux 2.6.17)
Stream socket peer closed connection, or shut down writing half
of connection. The _GNU_SOURCE feature test macro must be
defined (before including any header files) in order to obtain
this definition.
POLLERR
Error condition (output only).
POLLHUP
Hang up (output only).
POLLNVAL
Invalid request: fd not open (output only).
Related
From the man page of write()
Note that a successful write() may transfer fewer than count bytes.
Such partial writes can occur for various reasons; for example,
because there was insufficient space on the disk device to write all
of the requested bytes, or because a blocked write() to a socket,
pipe, or similar was interrupted by a signal handler after it had
transferred some, but before it had transferred all of the requested
bytes. In the event of a partial write, the caller can make another
write() call to transfer the remaining bytes. The subsequent call
will either transfer further bytes or may result in an error (e.g.,
if the disk is now full).
I have the following questions
1) In the case of write() being interrupted by signal handler after a partial transfer, will write() set the errno to EINTR ?
2) If errno is not set, is there a way to identify such an event with out extra piece of code (Like installing signal disposition and setting a flag value to true) ?
Note : The further write() calls are successful in transferring the remaining bytes after the event of signal interrupt.
To answer your individual numbered questions:
errno is only meaningful after one of the standard functions returns a value indicating an error - for write, -1 - and before any other standard function or application code that might clobber it is called. So no, if write returns a short write, errno will not be set to anything meaningful. If it's equal to EINTR, it just happens to be; this is not something meaningful you can interpret.
The way you identify such an event is by the return value being strictly less than the nbytes argument. This doesn't actually tell you the cause of the short write, so it could be something else like running out of space. If you need to know, you need to arrange for the signal handler to inform you. But in almost all cases you don't actually need to know.
Regarding the note, if write is returning the full nbytes after a signal arriving, the signal handler was non-interrupting. This is the default on Linux with any modern libc (glibc, musl, anything but libc5 basically), and it's almost always the right thing. If you actually want interrupting signals you have to install the signal handler with sigaction and the SA_RESTART flag clear. (And conversely if you're installing signal handlers you want to have the normal, reasonable, non-interrupting behavior, for portability you should use sigaction and set the SA_RESTART flag rather than using the legacy function signal).
Let's try it and see:
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
static void handle_sigalrm(int sig) {
}
int main(void) {
struct sigaction act;
memset(&act, 0, sizeof act);
act.sa_handler = handle_sigalrm;
sigaction(SIGALRM, &act, NULL);
int fds[2];
pipe(fds);
int bufsize = fcntl(fds[1], F_GETPIPE_SZ) + 10;
char *buf = calloc(bufsize, 1);
ssize_t written;
printf("will attempt to write %d bytes and EINTR is %d\n", bufsize, EINTR);
alarm(1);
errno = 0;
written = write(fds[1], buf, bufsize);
printf("write returned %td and errno is %d\n", written, errno);
return 0;
}
That program makes a pipe that nothing will ever read from, does a write to it that's bigger than the kernel's buffer, and arranges for a signal handler to run while the write is blocking. On my system, it prints this:
will attempt to write 65546 bytes and EINTR is 4
write returned 65536 and errno is 0
Thus, the answer to "In the case of write() being interrupted by signal handler after a partial transfer, will write() set the errno to EINTR?" is "no, it won't".
I find the poll() function quite useful for multiplexing pipes and sockets, but I wanted to extend on that and poll my own mediums, as in implement my own pipe and have it work with poll for POLLIN and POLLOUT events, How would I do that?
int self = GenerateMyPipe();
int sock = socket(...);
struct pollfd fd[2];
//Init Pollfd and Stuff...
poll(fd, 2, -1);
...
Thanks for reading...
There's no standard POSIX method for this, but on Linux you can use eventfd()
eventfd() creates an "eventfd object" that can be used as an event
wait/notify mechanism by user-space applications, and by the kernel
to notify user-space applications of events. The object contains an
unsigned 64-bit integer (uint64_t) counter that is maintained by the
kernel. This counter is initialized with the value specified in the
argument initval.
...
The returned file descriptor supports poll(2) (and analogously
epoll(7)) and select(2), as follows:
The file descriptor is readable (the select(2) readfds
argument; the poll(2) POLLIN flag) if the counter has a
value greater than 0.
The file descriptor is writable (the select(2) writefds
argument; the poll(2) POLLOUT flag) if it is possible to
write a value of at least "1" without blocking.
You change the counter by writing to the descriptor.
i have the following case
void foo() {
printf("hi\n");
while(1);
}
int main(void)
{
struct sigaction temp;
temp.sa_handler = &foo;
sigfillset(&temp.sa_mask);
sigdelset(&temp.sa_mask, SIGVTALRM);
sigdelset(&temp.sa_mask, SIGINT );
sigaction(SIGVTALRM, &temp, NULL);
struct itimerval tv;
tv.it_value.tv_sec = 2; /* first time interval, seconds part */
tv.it_value.tv_usec = 0; /* first time interval, microseconds part */
tv.it_interval.tv_sec = 2; /* following time intervals, seconds part */
tv.it_interval.tv_usec = 0; /* following time intervals, microseconds part */
if (setitimer(ITIMER_VIRTUAL, &tv, NULL)){
perror(NULL);
}
while(1);
return 0;
}
all I want is that every 2 seconds foo will be called (foo actually does some other stuff other than while(1), just assume foo run takes more than 2 seconds), after 2 seconds foo is indeed called but then no other call is made untill foo returns. I tried playing with the signal masks (hence the sigfillset) but also when simply calling signal(SIGVTALRM, foo) no changes are made in the result. I also tried having the itimerval and the sigactions variables declared outside main and it didn't quite affect anything.
is the thing I'm trying to do even possible?
thanks!
reference: <http://www.gnu.org/software/libc/manual/html_node/Signals-in-Handler.html>
24.4.4 Signals Arriving While a Handler Runs
What happens if another signal arrives while your signal handler function is running?
When the handler for a particular signal is invoked, that signal is automatically blocked until the handler returns. That means that if two signals of the same kind arrive close together, the second one will be held until the first has been handled. (The handler can explicitly unblock the signal using sigprocmask, if you want to allow more signals of this type to arrive; see Process Signal Mask.)
However, your handler can still be interrupted by delivery of another kind of signal. To avoid this, you can use the sa_mask member of the action structure passed to sigaction to explicitly specify which signals should be blocked while the signal handler runs. These signals are in addition to the signal for which the handler was invoked, and any other signals that are normally blocked by the process. See Blocking for Handler.
When the handler returns, the set of blocked signals is restored to the value it had before the handler ran. So using sigprocmask inside the handler only affects what signals can arrive during the execution of the handler itself, not what signals can arrive once the handler returns.
Portability Note: Always use sigaction to establish a handler for a signal that you expect to receive asynchronously, if you want your program to work properly on System V Unix. On this system, the handling of a signal whose handler was established with signal automatically sets the signal’s action back to SIG_DFL, and the handler must re-establish itself each time it runs. This practice, while inconvenient, does work when signals cannot arrive in succession. However, if another signal can arrive right away, it may arrive before the handler can re-establish itself. Then the second signal would receive the default handling, which could terminate the process.
reference:<http://www.gnu.org/software/libc/manual/html_node/Process-Signal-Mask.html#Process-Signal-Mask>
24.7.3 Process Signal Mask
The collection of signals that are currently blocked is called the signal mask. Each process has its own signal mask. When you create a new process (see Creating a Process), it inherits its parent’s mask. You can block or unblock signals with total flexibility by modifying the signal mask.
The prototype for the sigprocmask function is in signal.h.
Note that you must not use sigprocmask in multi-threaded processes, because each thread has its own signal mask and there is no single process signal mask. According to POSIX, the behavior of sigprocmask in a multi-threaded process is “unspecified”. Instead, use pthread_sigmask.
Function: int sigprocmask (int how, const sigset_t *restrict set, sigset_t *restrict oldset)
Preliminary: | MT-Unsafe race:sigprocmask/bsd(SIG_UNBLOCK) | AS-Unsafe lock/hurd | AC-Unsafe lock/hurd | See POSIX Safety Concepts.
The sigprocmask function is used to examine or change the calling process’s signal mask. The how argument determines how the signal mask is changed, and must be one of the following values:
SIG_BLOCK
Block the signals in set—add them to the existing mask. In other words, the new mask is the union of the existing mask and set.
SIG_UNBLOCK
Unblock the signals in set—remove them from the existing mask.
SIG_SETMASK
Use set for the mask; ignore the previous value of the mask.
The last argument, oldset, is used to return information about the old process signal mask. If you just want to change the mask without looking at it, pass a null pointer as the oldset argument. Similarly, if you want to know what’s in the mask without changing it, pass a null pointer for set (in this case the how argument is not significant). The oldset argument is often used to remember the previous signal mask in order to restore it later. (Since the signal mask is inherited over fork and exec calls, you can’t predict what its contents are when your program starts running.)
If invoking sigprocmask causes any pending signals to be unblocked, at least one of those signals is delivered to the process before sigprocmask returns. The order in which pending signals are delivered is not specified, but you can control the order explicitly by making multiple sigprocmask calls to unblock various signals one at a time.
The sigprocmask function returns 0 if successful, and -1 to indicate an error. The following errno error conditions are defined for this function:
EINVAL
The how argument is invalid.
You can’t block the SIGKILL and SIGSTOP signals, but if the signal set includes these, sigprocmask just ignores them instead of returning an error status.
Remember, too, that blocking program error signals such as SIGFPE leads to undesirable results for signals generated by an actual program error (as opposed to signals sent with raise or kill). This is because your program may be too broken to be able to continue executing to a point where the signal is unblocked again. See Program Error Signals.
I know that this has been answered and accepted already but I made tiny changes to the OP's question as follows in accordance with my comments and had a successful result (foo being called every 2 seconds, ad infinitum)
Note that addition of the memset of the temp variable and the changing from SIGVTALRM to SIGALRM.
#include <stdio.h>
#include <sys/time.h>
void foo() {
printf("hi\n");
}
int main(int argc, char **argv)
{
struct sigaction temp;
memset(&temp, 0, sizeof(temp));
temp.sa_handler = &foo;
sigfillset(&temp.sa_mask);
sigdelset(&temp.sa_mask, SIGALRM);
sigdelset(&temp.sa_mask, SIGINT );
sigaction(SIGALRM, &temp, NULL);
struct itimerval tv;
tv.it_value.tv_sec = 2; /* first time interval, seconds part */
tv.it_value.tv_usec = 0; /* first time interval, microseconds part */
tv.it_interval.tv_sec = 2; /* following time intervals, seconds part */
tv.it_interval.tv_usec = 0; /* following time intervals, microseconds part */
if (setitimer(ITIMER_REAL, &tv, NULL)){
fprintf (stderr, "cannot start timer\n");
perror(NULL);
}
while(1) {
fprintf (stdout, "sleep 1\n");
sleep (1);
}
return 0;
}
I have been pulling my hairs for real strange issue. The kernel module is unable to send signal to user application (or user app is unable to receive) without printk, have to do dummy printk after or before sending the signal.
Actually, it works great even with empty printk. But, i am trying to understand whats happening.
Any thoughts?
Here is whats happening:
A - kernel)
Char device type module gets interrupt.
It extracts the data and send signal to user.
/* have to do printk here */
Return IRQ handle.
B- user)
Receives the signal.
issues a system call and read the data from char device's buffer . (copy_to_user)
kernel:
void irq_handler(){
int i;
for(i =0; i < 32; i++)
GPIOdata[i] = read_gpio_status(i);
struct task_struct *p = find_task_by_pid(processinfo.pid);
if (NULL == p)
return;
send_sig(SIGUSR1, p, 0);
/* have to add printk here */
return IRQ_HANDLED
}
user:
void signal_handler(int sig) {
char data[32];
ioctl(fd, READ_Data_from_Char_device, &data);
}
If you are using signal not sigaction for setting handler, then remember, that signal removes handler after getting a signal. And you should mask the signal, so it will not interrupt your process when running inside signal handler. I'ma also not sure about system call ioctl inside handler (look at man7 signal under section Async-signal-safe functions).
Calls to printk might slow down execution of other operations (because they are blocked on I/O or buffering) around these calls, so they can make synchronization slower (thus any mistakes in synchronization may not occur).
I've found that on Linux, by making my own call to the rt_sigqueue syscall, I can put whatever I like in the si_uid and si_pid fields and the call succeeds and happily delivers the incorrect values. Naturally the uid restrictions on sending signals provide some protection against this kind of spoofing, but I'm worried it may be dangerous to rely on this information. Is there any good documentation on the topic I could read? Why does Linux allow the obviously-incorrect behavior of letting the caller specify the siginfo parameters rather than generating them in kernelspace? It seems nonsensical, especially since extra sys
calls (and thus performance cost) may be required in order to get the uid/gid in userspace.
Edit: Based on my reading of POSIX (emphasis added by me):
If si_code is SI_USER or SI_QUEUE, [XSI] or any value less than or equal to 0, then the signal was generated by a process and si_pid and si_uid shall be set to the process ID and the real user ID of the sender, respectively.
I believe this behavior by Linux is non-conformant and a serious bug.
That section of the POSIX page you quote also lists what si-code means, and here's the meaning:
SI_QUEUE
The signal was sent by the sigqueue() function.
That section goes on to say:
If the signal was not generated by one
of the functions or events listed
above, si_code shall be set either
to one of the signal-specific values
described in XBD , or to an
implementation-defined value that is
not equal to any of the values defined
above.
Nothing is violated if only the sigqueue() function uses SI_QUEUE. Your scenario involves code other than the sigqueue() function using SI_QUEUE The question is whether POSIX envisions an operating system enforcing that only a specified library function (as opposed to some function which is not a POSIX-defined library function) be permitted to make a system call with certain characteristics. I believe the answer is "no".
EDIT as of 2011-03-26, 14:00 PST:
This edit is in response to R..'s comment from eight hours ago, since the page wouldn't let me leave an adequately voluminous comment:
I think you're basically right. But either a system is POSIX compliant or it is not. If a non-library function does a syscall which results in a non-compliant combination of uid, pid, and 'si_code', then the second statement I quoted makes it clear that the call itself is not compliant. One can interpret this in two ways. One ways is: "If a user breaks this rule, then he makes the system non-compliant." But you're right, I think that's silly. What good is a system when any nonprivileged user can make it noncompliant? The fix, as I see it, is somehow to have the system know that it's not the library 'sigqueue()' making the system call, then the kernel itself should set 'si_code' to something other than 'SI_QUEUE', and leave the uid and pid as you set them. In my opinion, you should raise this with the kernel folks. They may have difficulty, however; I don't know of any secure way for them to detect whether a syscall is made by a particular library function, seeing as how the library functions. almost by definition, are merely convenience wrappers around the syscalls. And that may be the position they take, which I know will be a disappointment.
(voluminous) EDIT as of 2011-03-26, 18:00 PST:
Again because of limitations on comment length.
This is in response to R..'s comment of about an hour ago.
I'm a little new to the syscall subject, so please bear with me.
By "the kernel sysqueue syscall", do you mean the `__NR_rt_sigqueueinfo' call? That's the only one that I found when I did this:
grep -Ri 'NR.*queue' /usr/include
If that's the case, I think I'm not understanding your original point. The kernel will let (non-root) me use SI-QUEUE with a faked pid and uid without error. If I have the sending side coded thus:
#include <sys/syscall.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,
char **argv
)
{
long john_silver;
siginfo_t my_siginfo;
if(argc!=2)
{
fprintf(stderr,"missing pid argument\n");
exit(1);
}
john_silver=strtol(argv[1],NULL,0);
if(kill(john_silver,SIGUSR1))
{
fprintf(stderr,"kill() fail\n");
exit(1);
}
sleep(1);
my_siginfo.si_signo=SIGUSR1;
my_siginfo.si_code=SI_QUEUE;
my_siginfo.si_pid=getpid();
my_siginfo.si_uid=getuid();
my_siginfo.si_value.sival_int=41;
if(syscall(__NR_rt_sigqueueinfo,john_silver,SIGUSR1,&my_siginfo))
{
perror("syscall()");
exit(1);
}
sleep(1);
my_siginfo.si_signo=SIGUSR2;
my_siginfo.si_code=SI_QUEUE;
my_siginfo.si_pid=getpid()+1;
my_siginfo.si_uid=getuid()+1;
my_siginfo.si_value.sival_int=42;
if(syscall(__NR_rt_sigqueueinfo,john_silver,SIGUSR2,&my_siginfo))
{
perror("syscall()");
exit(1);
}
return 0;
} /* main() */
and the receiving side coded thus:
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int signaled_flag=0;
siginfo_t received_information;
void
my_handler(int signal_number,
siginfo_t *signal_information,
void *we_ignore_this
)
{
memmove(&received_information,
signal_information,
sizeof(received_information)
);
signaled_flag=1;
} /* my_handler() */
/*--------------------------------------------------------------------------*/
int
main(void)
{
pid_t myself;
struct sigaction the_action;
myself=getpid();
printf("signal receiver is process %d\n",myself);
the_action.sa_sigaction=my_handler;
sigemptyset(&the_action.sa_mask);
the_action.sa_flags=SA_SIGINFO;
if(sigaction(SIGUSR1,&the_action,NULL))
{
fprintf(stderr,"sigaction(SIGUSR1) fail\n");
exit(1);
}
if(sigaction(SIGUSR2,&the_action,NULL))
{
fprintf(stderr,"sigaction(SIGUSR2) fail\n");
exit(1);
}
for(;;)
{
while(!signaled_flag)
{
sleep(1);
}
printf("si_signo: %d\n",received_information.si_signo);
printf("si_pid : %d\n",received_information.si_pid );
printf("si_uid : %d\n",received_information.si_uid );
if(received_information.si_signo==SIGUSR2)
{
break;
}
signaled_flag=0;
}
return 0;
} /* main() */
I can then run (non-root) the receiving side thus:
wally:~/tmp/20110326$ receive
signal receiver is process 9023
si_signo: 10
si_pid : 9055
si_uid : 4000
si_signo: 10
si_pid : 9055
si_uid : 4000
si_signo: 12
si_pid : 9056
si_uid : 4001
wally:~/tmp/20110326$
And see this (non-root) on the send end:
wally:~/tmp/20110326$ send 9023
wally:~/tmp/20110326$
As you can see, the third event has spoofed pid and uid. Isn't that what you originally objected to? There's no EINVAL or EPERM in sight. I guess I'm confused.
I agree that si_uid and si_pid should be trustworthy, and if they are not it is a bug. However, this is only required if the signal is SIGCHLD generated by a state change of a child process, or if si_code is SI_USER or SI_QUEUE, or if the system supports the XSI option and si_code <= 0. Linux/glibc also pass si_uid and si_pid values in other cases; these are often not trustworthy but that is not a POSIX conformance issue.
Of course, for kill() the signal may not be queued in which case the siginfo_t does not provide any additional information.
The reason that rt_sigqueueinfo allows more than just SI_QUEUE is probably to allow implementing POSIX asynchronous I/O, message queues and per-process timers with minimal kernel support. Implementing these in userland requires the ability to send a signal with SI_ASYNCIO, SI_MESGQ and SI_TIMER respectively. I do not know how glibc allocates the resources to queue the signal beforehand; to me it looks like it does not and simply hopes rt_sigqueueinfo does not fail. POSIX clearly forbids discarding a timer expiration (async I/O completion, message arrival on a message queue) notification because too many signals are queued at the time of the expiration; the implementation should have rejected the creation or registration if there were insufficient resources. The objects have been defined carefully such that each I/O request, message queue or timer can have at most one signal in flight at a time.