read on inotify descriptor is blocked forever - c++

My program uses inotify for monitoring changes on files.
My code is as following:
fd = inotify_init();
wd = inotify_add_watch(fd, "./test.txt", IN_ALL_EVENTS);
len = read(fd, buff, BUFF_SIZE);
while (i < len) {
struct inotify_event *pevent = (struct inotify_event *) &buff[i];
//process events
i += sizeof(struct inotify_event) + pevent->len;
}
However, after I got several events for the first change in the monitored files (event IN_OPEN, IN_MODIFY, IN_ACESS, etc.), later changes in the monitored files does generate any other events ==> my program hang out at the read function (the read is blocked)
Could you guys help me explain this error.

please show what operations actually happen to "./test.txt" and more about your code (buff, BUFF_SIZE). And here is some point for you to check:
There are some special events like IN_IGNORED which may remove watch from the file
I suggest to use select/poll/epoll to monitor the fd rather than BLOCKING read on it.

Use fcntl to make the file descriptor non-blocking.

Related

QSocketNotifier opened on a FIFO keeps firing even if I read everything

In my code I open a FIFO (created with mkfifo) and then I proceed to use a QSocketNotifier to receive notifications of incoming data, to read it while it arrives.
// create the FIFO
if(!mkfifo(SERIAL_FIFO, 0600)) {
// nonblocking open (even open itself would block until a first write)
in_fifo = ::open(SERIAL_FIFO, O_RDONLY | O_NONBLOCK);
if(in_fifo >= 0) {
// create notifier
in_fifo_notifier = new QSocketNotifier(in_fifo, QSocketNotifier::Read, this);
connect(&*in_fifo_notifier, &QSocketNotifier::activated,
this, [this](QSocketDescriptor /*socket*/, QSocketNotifier::Type /*type*/){
// copy all the available data
char buf[4096];
for(;;) {
ssize_t rl = ::read(in_fifo, buf, sizeof(buf));
if(rl <= 0) break;
::write(out_fd, buf, rl);
}
});
}
The problem is that, whenever someone writes on the other end of the pipe, the signal keeps getting activated (with associated 100% CPU usage), even though every time I read all the data. Where's the problem?
Ultimately, this is just a variation over the problem described here, as Qt under the hood uses select/epoll machinery to implement QSocketNotifier. Opening the FIFO as O_RDWR fixes the problem.

How to stop a C++ blocking read call

I'm reading CAN-BUS traffic under SocketCAN and C++ in GNU/Linux. I've found that the read call is blocking, and I'm struggling to figure out how to stop my program properly when I don't want to keep reading.
Of course, I could hit Ctrl+C if I've invoked the program from the terminal, but the point is to find a way to do it programmatically when some condition is met (e.g., record for 5 seconds, or when some event happens, like a flag is raised). A timeout could work, or something like a signal, but I don't know how to do it properly.
// Read (blocking)
nbytes = read(s, &frame, sizeof(struct can_frame));
You don't.
Use a method like select or epoll to determine whether the socket has activity before beginning the read. Then it will not actually block.
The select/epoll call is itself blocking, but can be given a timeout so that you always have an escape route (or, in the case of epoll, the lovely epollfd for immediate triggering of a breakout).
Read is always blocking... you want to only read if data is waiting... so consider doing a poll on the socket first to see if data is available and if so THEN read it. You can loop over doing the poll until you no longer want to read anymore...
bool pollIn(int fd)
{
bool returnValue{false};
struct pollfd *pfd;
pfd = calloc(1, sizeof(struct pollfd));
pfd.fd = fd;
pfd.events = POLLIN;
int pollReturn{-1};
pollReturn = poll(pfd, 1, 0);
if (pollReturn > 0)
{
if (pfd.revents & POLLIN)
{
returnValue = true;
}
}
free(pfd);
return(returnValue);
}
The above should return if there is data waiting at the socket file descriptor.
while(!exitCondition)
{
if(pollIn(fd))
{
nbytes = read(fd, &frame, sizeof(struct can_frame));
// other stuff you need to do with your read
}
}

Pipe + select: select never woken up

I'm building a small io service that checks read and write availability of some fds.
To do that, I have a thread dedicated to the select without any timeout so that the select only wakes up when a fd becomes available.
However, I sometimes want to force select to be woken up on specific events. To do so, I simply use a pipe, watch for its read availability and write on it when I want to wake up the select call.
This works most of the time, but it sometimes happens that nothing happen when I write to the pipe. So the select call remains blocked indefinitely.
Here is a part of the code I use:
Select thread:
FD_ZERO(&rd_set);
//! set some other fds...
FD_SET(m_notif_pipe_fds[0], &rd_set);
select(max_fd + 1, &rd_set, &wr_set, nullptr, nullptr);
if (FD_ISSET(m_notif_pipe_fds[0], &rd_set)) {
char buf[1024];
read(m_notif_pipe_fds[0], buf, 1024);
}
Notify thread:
write(m_notif_pipe_fds[1], "a", 1);
The max_fd variable has effectively been set to the highest fd value (not the number of fd to watch which is a common error).
Any idea?
I'd suggest you to make your pipe non-blocking
int flags = fcntl(m_notif_pipe_fd[1], F_GETFL, 0);
assert(flags != -1);
fcntl(m_notif_pipe_fd[1], F_SETFL, flags | O_NONBLOCK);
and set pipe buffer size to 1
int pipe_sz = fcntl(m_notif_pipe_fd[1], F_SETPIPE_SZ, 1);
See this question

Showing a message in the terminal from which signal was sent

My process in running as daemon.
I want to reload the configuration using signal.
The problem is that if configuration is wrong it should error message in the tty form which signal was sent.
Is there a way to do this?
Is it recommended way?
If it is not recommended way. What will be a more appropriate way to check if it was successful or not?
For getting pid of signal source, you need to use sa_sigaction instead of sa_handler when you set signal handlers:
static pid_t g_killer_pid = 0;
static void signal_handler( int num, siginfo_t *info, void* blabla )
{
g_killer_pid = info->si_pid;
}
int main(void)
{
struct sigaction sa;
memset( &sa, 0, sizeof(sa) );
sa.sa_sigaction = &signal_handler;
sa.sa_flags = SA_SIGINFO;
sigaction( SIGTERM, &sa, NULL );
sigaction( SIGINT, &sa, NULL );
pause();
hello_killer( g_killer_pid );
return 0;
}
Now you have pid of the source process.
For getting terminal id of the source process is not so simple.
One way is read it from proc/<pid>/stat file. One number in the file is tty_nr.
tty_nr is little bit strange for me, so I don't know is this even portable stuff.
But it holds minor number, that can be used for opening correct terminal for writing:
static void hello_killer( pid_t killer )
{
char filename[200];
FILE* fil;
FILE* out;
int tty_nr;
sprintf( filename, "/proc/%ld/stat", (long int)killer );
fil = fopen( filename, "r" );
if( fil )
{
if( fscanf( fil, "%*s %*s %*s %*s %*s %*s %d ", &tty_nr ) == 1 )
{
sprintf( filename, "/dev/pts/%d", (tty_nr & 0xF) | ((tty_nr >> 20) & 0xFFF) );
out = fopen( filename, "a" );
if( out )
{
fprintf( out, "Hello!\n" );
fclose( out );
}
}
fclose( fil );
}
}
I am not sure is that /dev/pts trick correct/best way to do it. But it seems to work in my Linux box:
~ # killall temp_test
Hello!
~ #
I'm guessing you something like catching SIGUSR1 and then reload the configuration?
You should remember that signal handlers should be as small and quick as possible, and not do something that can cause another signal. So basically you should refrain from I/O as much as possible. What is probably the best way to do this is to have a very simple signal handler that only sets a flag, then in your main loop you check for this flag and then reload your configuration in the context of your main thread. There you can output to the console all you want.
You can do this, but there's no trivial way to do it. You need to arrange a mechanism for the daemon to feedback to the process sending the signal.
Some possible ways of doing that include:
Write the (timestamped) result to a file in a predetermined location.
Have the daemon maintain a shared memory segment with the information in a known structure.
Have the daemon listen on a named pipe/socket of some sort and give out feedback that way. (You could also send the reload command via that channel).
Have the thing that sends the signal and the daemon link against a shared library so that both are capable of validating the configuration file. Validate the file before raising the signal.
Of those a named pipe would be my first choice I think - you can restrict access to it with normal permissions and it's the easiest to make robust and correct.
I doubt, that you can determine the source of the signal and even, if you could so, it don't have to be a terminal. What about using a simple tcp/ip protocol? Accept tcp/ip connections on a special port. Read a command until a first new line. If that command is "reconfigure", do the reconfiguration and send a message over the established TCP/IP connection.

Monitoring file using inotify

I am using inotify to monitor a local file, for example "/root/temp" using
inotify_add_watch(fd, "/root/temp", mask).
When this file is deleted, the program will be blocked by read(fd, buf, bufSize) function. Even if I create a new "/root/temp" file, the program is still block by read function. I am wondering if inotify can detect that the monitored file is created and the read function can get something from fd so that read will not be blocked forever.
Here is my code:
uint32_t mask = IN_ALL_EVENTS;
int fd = inotify_init();
int wd = inotify_add_watch(fd, "/root/temp", mask);
char *buf = new char[1000];
int nbytes = read(fd, buf, 500);
I monitored all events.
The problem is that read is a blocking operation by default.
If you don't want it to block, use select or poll before read. For example:
struct pollfd pfd = { fd, POLLIN, 0 };
int ret = poll(&pfd, 1, 50); // timeout of 50ms
if (ret < 0) {
fprintf(stderr, "poll failed: %s\n", strerror(errno));
} else if (ret == 0) {
// Timeout with no events, move on.
} else {
// Process the new event.
struct inotify_event event;
int nbytes = read(fd, &event, sizeof(event));
// Do what you need...
}
Note: untested code.
In order to see a new file created, you need to watch the directory, not the file. Watching a file should see when it is deleted (IN_DELETE_SELF) but may not spot if a new file is created with the same name.
You should probably watch the directory for IN_CREATE | IN_MOVED_TO to see newly created files (or files moved in from another place).
Some editors and other tools (e.g. rsync) may create a file under a different name, then rename it.