How to terminate write()

hi,

 I am trying to write a bulk to data to harddisk using write(). In between write operation, my application sends signal for termination. But write() call not exitting. EINTR not happening. How to terminate write(). Please help.

Regards,
hello

Which signal are you raising to try and terminate the write() call?

Are you sure that the signal you are raising isn’t set to be ignored?

I assume this signal is meant to go between 2 processes or is it going between 2 threads in the same process?

Tim

I think you need to clarify this. If I take what you say literally, you have a program that is writing to the hard drive, presumably in a loop. If that program sends a sign between write calls, why would write() exit, it’s not running? Also, by sending a signal, do you mean raising a signal? If so, on who?

I also don’t see why you need to terminate write. Generally speaking, write() will return almost immediately after the data has been transferred to the cache. If you are writing bulk data fast enough, you might be able to fill up the cache in which case your program would hang waiting for the their to be room in the cache. If at that point another program raises a signal on your program, after the file system replies, your program would either exit or the signal handler would be called. However the writing from cache would continue.

Yes, i have an application that is writing to the hard drive in a loop(Large size). If the user wishes to terminate the application, i need to stop write() immediately. For termination, i used signals. But write() not exitting with EINTR. It exits only after write operation is finished. Is this the expected behaviour. Is there any way to exit write() immediately after receiving a signal.

Regards,
hello

Well you are still seem to be holding back on information but I’m going to assume the following. You have an application that is writing in a loop, and you raise a signal on it which is caught by a signal handler, but you are noticing that the signal handler does not get control immediately. Also, the write return code indicates that the write completed. Does that sum it up? Here’s a possible explanation.

When you do a write() a message is sent to the file system process using message passing. As I mentioned in a previous post, if the cache is not full, write() will return immediately. Presumably this is not the case for you. So the cache is full when you do your write(). Your thread is then reply blocked waiting for the file system to empty enough of the cache so that it can store the data and reply. This is not necessarily the minimum amount of cache. The file system tries to optimize writes, so after a bunch of writes that go into the cache and return immediately, you might have to wait a bit.

At this point you raise the signal. An option undoubtedly used by the file system with message passing causes a pulse to be sent to the file system, but leaves the reply blocked thread hanging until the server thread replies. Such a server is not obligated to reply immediately. The pulse might not be received right away and even if it is, it might be ignored.

So you might be waiting for a large flush of dirty cache pages to disk.

If this is happening and by terminating immediately you want this flush to be skipped, you are sol. That’s not the way it works.

It’s also the case that by the time write() returns, from the point of view of the file system, the write has completed. Your signal probably would only interrupt the write if it occurs between the time your thread does it’s send and the file system returns from its receive. Since the file system is multi-threaded, that’s a very small window. I don’t think the file system interrupts its own call to the disk driver, which is where your system is probably spending most of it’s time.
So you are probably waiting for the disk driver to complete, something that a signal on your thread will not stop.

I hope this helps.

Thanks maschoen. I understood your point. But i am calling write() from a QNX C application. If the user wishes to terminate the application, by somehow i need to terminate write() without any delay. Is there any option for this ?

Well, if you don’t like the way write() is working due to cache, then change the way you are calling write() !

Open the disk file with the O_NONBLOCK flag. Now when the cache is full, write() will …

  1. fail with -1 and errno EAGAIN, or
  2. succeed, returning a number of bytes written -BUT- less than you requested.

You must change your logic to detect these two cases and retry the write() accordingly after some time passes.

Now your program remains “in control” and you can terminate whenever you wish. BTW, there is nothing QNX-specific here - its just the way POSIX calls work.

I have tried O_NONBLOCK. But write() not returning failure. Sample code is shown below

#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <atomic.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <sys/ioctl.h>

#define SIZE (800 * 1024 * 1024)

void handler(void)
{
printf(“in handler\n”);
}

int main(int argc, char *argv[])
{

long long unsigned int s32_ret_sts;
char* pu8_write_buff;
int s32_desc = -1;
int				s32_ret_val = 0;
int i;
struct sigaction 	t_action; 	/*  Signal structure */

memset(&t_action, 0, sizeof(struct sigaction));

t_action.sa_flags = SA_SIGINFO;
t_action.sa_handler = &handler;

s32_ret_val |= sigaction(SIGHUP,  &t_action, NULL);		/* hangup */
s32_ret_val |= sigaction(SIGINT,  &t_action, NULL);		/* interrupt */
s32_ret_val |= sigaction(SIGQUIT, &t_action, NULL);		/* quit */
s32_ret_val |= sigaction(SIGILL,  &t_action, NULL);		/* illegal instruction */
s32_ret_val |= sigaction(SIGTRAP, &t_action, NULL);		/* trace trap */
s32_ret_val |= sigaction(SIGIOT,  &t_action, NULL);		/* IOT instruction */
s32_ret_val |= sigaction(SIGABRT, &t_action, NULL);		/* Used by abort() function */
s32_ret_val |= sigaction(SIGFPE,  &t_action, NULL);		/* EMT instruction */
s32_ret_val |= sigaction(SIGBUS,  &t_action, NULL);		/* Bus error */
s32_ret_val |= sigaction(SIGSEGV, &t_action, NULL);		/* Segmentation violation */
s32_ret_val |= sigaction(SIGSYS,  &t_action, NULL);		/* Bad argument to system call */
s32_ret_val |= sigaction(SIGPIPE, &t_action, NULL);		/* Write on pipe with no reader */
s32_ret_val |= sigaction(SIGALRM, &t_action, NULL);		/* Real-time alarm clock */
s32_ret_val |= sigaction(SIGTERM, &t_action, NULL);		/* Software termination signal from kill */
s32_ret_val |= sigaction(SIGPWR,  &t_action, NULL);		/* Power-fail restart */
s32_ret_val |= sigaction(SIGPOLL, &t_action, NULL);		/* System V name for SIGIO */
s32_ret_val |= sigaction(SIGVTALRM, &t_action, NULL);	/* Virtual timer expired */
s32_ret_val |= sigaction(SIGXCPU, &t_action, NULL);		/* Exceeded CPU limit */
s32_ret_val |= sigaction(SIGXFSZ, &t_action, NULL);		/* Exceeded file size limit */
s32_ret_val |= sigaction(SIGUSR1, &t_action, NULL);	/* User-defined signal 2 */
s32_ret_val |= sigaction(SIGUSR2, &t_action, NULL);		/* User-defined signal 2 */
s32_ret_val |= sigaction(SIGRTMIN, &t_action, NULL);	/* User-defined signal - real-time */

pu8_write_buff =   malloc(SIZE);

for (i = 0; i < 10; i++)
{
	s32_desc = open64("/dev/hd0", O_WRONLY | O_NONBLOCK);
	if (-1 != s32_desc)
	{
		s32_ret_sts = write(s32_desc, pu8_write_buff, SIZE);

		if ((SIZE != s32_ret_sts) || (-1 == s32_ret_sts))
		{
			printf("Error %d\n", errno);
			break;
		}
		else
		{
			printf("Success %llu\n", s32_ret_sts);
		}
	}
	close(s32_desc);
}

return EXIT_SUCCESS;

}

Dennis, thanks for filling in. That’s what I get for never using anything else but QNX, :slight_smile:.

That leaves me with a question. If like our poster, I was to send a huge amount of data to the cache, and then I close the file and exit. Will the data be at the disk when the program exits, or could it still be being flushed? Maybe this depends on open options?

sorry, i didnt understand your reply.
I know there is nothing QNX-specific here.
Could you please clarify how to make the write() non blocking. Its not working for me.

Break your 800Meg write into smaller writes.

Thats the problem. The data cannot be split into smaller ones. 800Mb data should be written in a single write operation.

This makes no sense, sorry but it doesn’t. Either you break up the write or you wait for it to finish.

thank u

This is a “heavy weight lifting” type of discussion I’ve often witnessed. The task is to lift an incredibly heavy weight, and everyone wonders how to lift it, but no one works on decreasing the weight. :slight_smile:

So, some thoughts:

  • How much sense does it make to cancel a write operation? It will lead to an incompletely written file/data.
  • The statement of writing the 800 MB must be done in one write, and the statement that the write must be cancel-able in the middle of working, are contradicting each other.
  • Where do you get 800 MB of data. Is it uncompressed? Could you at least apply simple RLE (Runlength encoding) to reduce the amount - this will reduce the time write takes.
  • You could put the write operation into a separate thread. When the user cancels the application, it could close but the write thread could complete its work in the background.

BTW - after some research, if found the O_NONBLOCK open() flag does not work for block-disk operations. It does work for character-type drivers. Disk operations are considered “unblockable”. I verified that this is also true in Linux as well - O_NONBLOCK is ignored for disk files.

Thank you all for your great support concluding my issue.

Regards,
hello