Skip to content

Commit d0680fd

Browse files
Cynerdxiaoxiang781216
authored andcommitted
drivers/pipes: return after short write if buffer is full
The write should return even in case of O_NONBLOCK if at least some bytes were written. The previous state where always all bytes were written was breaking a common combination with poll, because poll would signal POLLOUT and some bytes would really be consumed but write could still block afterwards. That would prevent from execution returning to the poll loop again. None the less it is also the standard C library behavior for the write function.
1 parent 4ba8723 commit d0680fd

File tree

1 file changed

+43
-84
lines changed

1 file changed

+43
-84
lines changed

drivers/pipes/pipe_common.c

Lines changed: 43 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,6 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
506506
FAR struct inode *inode = filep->f_inode;
507507
FAR struct pipe_dev_s *dev = inode->i_private;
508508
ssize_t nwritten = 0;
509-
ssize_t last;
510509
int ret;
511510

512511
DEBUGASSERT(dev);
@@ -546,97 +545,32 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
546545
return ret;
547546
}
548547

549-
/* Loop until all of the bytes have been written */
548+
/* REVISIT: "If all file descriptors referring to the read end of a
549+
* pipe have been closed, then a write will cause a SIGPIPE signal to
550+
* be generated for the calling process. If the calling process is
551+
* ignoring this signal, then write(2) fails with the error EPIPE."
552+
*/
550553

551-
last = 0;
552-
for (; ; )
554+
if (dev->d_nreaders <= 0 && PIPE_IS_POLICY_0(dev->d_flags))
553555
{
554-
/* REVISIT: "If all file descriptors referring to the read end of a
555-
* pipe have been closed, then a write will cause a SIGPIPE signal to
556-
* be generated for the calling process. If the calling process is
557-
* ignoring this signal, then write(2) fails with the error EPIPE."
558-
*/
559-
560-
if (dev->d_nreaders <= 0 && PIPE_IS_POLICY_0(dev->d_flags))
561-
{
562-
nxrmutex_unlock(&dev->d_bflock);
563-
return nwritten == 0 ? -EPIPE : nwritten;
564-
}
556+
nxrmutex_unlock(&dev->d_bflock);
557+
return -EPIPE;
558+
}
565559

566-
/* Would the next write overflow the circular buffer? */
560+
/* Would the next write overflow the circular buffer? */
567561

568-
if (!circbuf_is_full(&dev->d_buffer))
562+
while (circbuf_is_full(&dev->d_buffer))
563+
{
564+
if (filep->f_oflags & O_NONBLOCK)
569565
{
570-
/* Loop until all of the bytes have been written */
571-
572-
nwritten += circbuf_write(&dev->d_buffer,
573-
buffer + nwritten, len - nwritten);
574-
575-
if ((size_t)nwritten == len)
576-
{
577-
/* Notify all poll/select waiters that they can read from the
578-
* FIFO when buffer used exceeds poll threshold.
579-
*/
580-
581-
if (circbuf_used(&dev->d_buffer) > dev->d_pollinthrd)
582-
{
583-
poll_notify(dev->d_fds, CONFIG_DEV_PIPE_NPOLLWAITERS,
584-
POLLIN);
585-
}
586-
587-
/* Yes.. Notify all of the waiting readers that more data is
588-
* available.
589-
*/
590-
591-
pipecommon_wakeup(&dev->d_rdsem);
592-
593-
/* Return the number of bytes written */
566+
/* If O_NONBLOCK was set, then return EGAIN. */
594567

595-
nxrmutex_unlock(&dev->d_bflock);
596-
return len;
597-
}
568+
nxrmutex_unlock(&dev->d_bflock);
569+
return -EAGAIN;
598570
}
599571
else
600572
{
601-
/* There is not enough room for the next byte. Was anything
602-
* written in this pass?
603-
*/
604-
605-
if (last < nwritten)
606-
{
607-
/* Notify all poll/select waiters that they can read from the
608-
* FIFO.
609-
*/
610-
611-
poll_notify(dev->d_fds, CONFIG_DEV_PIPE_NPOLLWAITERS, POLLIN);
612-
613-
/* Yes.. Notify all of the waiting readers that more data is
614-
* available.
615-
*/
616-
617-
pipecommon_wakeup(&dev->d_rdsem);
618-
}
619-
620-
last = nwritten;
621-
622-
/* If O_NONBLOCK was set, then return partial bytes written or
623-
* EGAIN.
624-
*/
625-
626-
if (filep->f_oflags & O_NONBLOCK)
627-
{
628-
if (nwritten == 0)
629-
{
630-
nwritten = -EAGAIN;
631-
}
632-
633-
nxrmutex_unlock(&dev->d_bflock);
634-
return nwritten;
635-
}
636-
637-
/* There is more to be written.. wait for data to be removed from
638-
* the pipe
639-
*/
573+
/* Wait for data to be removed from the pipe. */
640574

641575
nxrmutex_unlock(&dev->d_bflock);
642576
ret = nxsem_wait(&dev->d_wrsem);
@@ -646,10 +580,35 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
646580
* received or if the task was canceled.
647581
*/
648582

649-
return nwritten == 0 ? (ssize_t)ret : nwritten;
583+
return (ssize_t)ret;
650584
}
651585
}
652586
}
587+
588+
/* Write data to buffer. */
589+
590+
nwritten = circbuf_write(&dev->d_buffer, buffer, len);
591+
592+
/* Notify all poll/select waiters that they can read from the
593+
* FIFO when buffer used exceeds poll threshold.
594+
*/
595+
596+
if (circbuf_used(&dev->d_buffer) > dev->d_pollinthrd)
597+
{
598+
poll_notify(dev->d_fds, CONFIG_DEV_PIPE_NPOLLWAITERS,
599+
POLLIN);
600+
}
601+
602+
/* Yes.. Notify all of the waiting readers that more data is
603+
* available.
604+
*/
605+
606+
pipecommon_wakeup(&dev->d_rdsem);
607+
608+
/* Return the number of bytes written */
609+
610+
nxrmutex_unlock(&dev->d_bflock);
611+
return nwritten;
653612
}
654613

655614
/****************************************************************************

0 commit comments

Comments
 (0)