* Implemented a different way to notify waiting read()s when a file descriptor
is closed; their ReadRequest will now be notified with B_FILE_ERROR. * This is a better fix for #5947, though note that I left the changes in Inode::ReadDataFromBuffer() in place, as I think this is what POSIX requires. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37860 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -51,8 +51,11 @@
|
||||
|
||||
namespace fifo {
|
||||
|
||||
|
||||
struct file_cookie;
|
||||
class Inode;
|
||||
|
||||
|
||||
class RingBuffer {
|
||||
public:
|
||||
RingBuffer();
|
||||
@@ -76,9 +79,10 @@ class RingBuffer {
|
||||
|
||||
class ReadRequest : public DoublyLinkedListLinkImpl<ReadRequest> {
|
||||
public:
|
||||
ReadRequest()
|
||||
ReadRequest(file_cookie* cookie)
|
||||
:
|
||||
fThread(thread_get_current_thread()),
|
||||
fCookie(cookie),
|
||||
fNotified(true)
|
||||
{
|
||||
B_INITIALIZE_SPINLOCK(&fLock);
|
||||
@@ -90,21 +94,27 @@ class ReadRequest : public DoublyLinkedListLinkImpl<ReadRequest> {
|
||||
fNotified = notified;
|
||||
}
|
||||
|
||||
void Notify()
|
||||
void Notify(status_t status = B_OK)
|
||||
{
|
||||
InterruptsSpinLocker _(fLock);
|
||||
TRACE("ReadRequest %p::Notify(), fNotified %d\n", this, fNotified);
|
||||
|
||||
if (!fNotified) {
|
||||
SpinLocker threadLocker(gThreadSpinlock);
|
||||
thread_unblock_locked(fThread, B_OK);
|
||||
thread_unblock_locked(fThread, status);
|
||||
fNotified = true;
|
||||
}
|
||||
}
|
||||
|
||||
file_cookie* Cookie() const
|
||||
{
|
||||
return fCookie;
|
||||
}
|
||||
|
||||
private:
|
||||
spinlock fLock;
|
||||
struct thread* fThread;
|
||||
file_cookie* fCookie;
|
||||
volatile bool fNotified;
|
||||
};
|
||||
|
||||
@@ -165,7 +175,7 @@ class Inode {
|
||||
void NotifyEndClosed(bool writer);
|
||||
|
||||
void Open(int openMode);
|
||||
void Close(int openMode);
|
||||
void Close(int openMode, file_cookie* cookie);
|
||||
int32 ReaderCount() const { return fReaderCount; }
|
||||
int32 WriterCount() const { return fWriterCount; }
|
||||
|
||||
@@ -215,7 +225,7 @@ struct file_cookie {
|
||||
};
|
||||
|
||||
|
||||
//---------------------
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
RingBuffer::RingBuffer()
|
||||
@@ -390,7 +400,7 @@ Inode::WriteDataToBuffer(const void *_data, size_t *_length, bool nonBlocking)
|
||||
}
|
||||
|
||||
// write only as long as there are readers left
|
||||
if (fReaderCount == 0) {
|
||||
if (fActive && fReaderCount == 0) {
|
||||
if (written == 0)
|
||||
send_signal(find_thread(NULL), SIGPIPE);
|
||||
return EPIPE;
|
||||
@@ -615,12 +625,19 @@ Inode::Open(int openMode)
|
||||
|
||||
|
||||
void
|
||||
Inode::Close(int openMode)
|
||||
Inode::Close(int openMode, file_cookie* cookie)
|
||||
{
|
||||
TRACE("Inode %p::Close(openMode = %d)\n", this, openMode);
|
||||
|
||||
MutexLocker locker(RequestLock());
|
||||
|
||||
// Notify all currently reading file descriptors
|
||||
ReadRequestList::Iterator iterator = fReadRequests.GetIterator();
|
||||
while (ReadRequest* request = iterator.Next()) {
|
||||
if (request->Cookie() == cookie)
|
||||
request->Notify(B_FILE_ERROR);
|
||||
}
|
||||
|
||||
if ((openMode & O_ACCMODE) == O_WRONLY && --fWriterCount == 0)
|
||||
NotifyEndClosed(true);
|
||||
|
||||
@@ -750,7 +767,7 @@ fifo_close(fs_volume *volume, fs_vnode *vnode, void *_cookie)
|
||||
file_cookie *cookie = (file_cookie *)_cookie;
|
||||
FIFOInode* fifo = (FIFOInode*)vnode->private_node;
|
||||
|
||||
fifo->Close(cookie->open_mode);
|
||||
fifo->Close(cookie->open_mode, cookie);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -802,7 +819,7 @@ fifo_read(fs_volume *_volume, fs_vnode *_node, void *_cookie,
|
||||
|
||||
// issue read request
|
||||
|
||||
ReadRequest request;
|
||||
ReadRequest request(cookie);
|
||||
inode->AddReadRequest(request);
|
||||
|
||||
TRACE(" issue read request %p\n", &request);
|
||||
|
||||
Reference in New Issue
Block a user