void Inode::NotifyEndClosed(bool writer) { TRACE("Inode %p::%s(%s)\n", this, __FUNCTION__, writer ? "writer" : "reader"); if (writer) { // Our last writer has been closed; if the pipe // contains no data, unlock all waiting readers TRACE(" buffer readable: %zu\n", fBuffer.Readable()); if (fBuffer.Readable() == 0) { ReadRequestList::Iterator iterator = fReadRequests.GetIterator(); while (ReadRequest* request = iterator.Next()) request->Notify(); if (fReadSelectSyncPool) notify_select_event_pool(fReadSelectSyncPool, B_SELECT_READ); } } else { // Last reader is gone. Wake up all writers. fWriteCondition.NotifyAll(); if (fWriteSelectSyncPool) { notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_WRITE); notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_ERROR); } } }
status_t Inode::ReadDataFromBuffer(void* data, size_t* _length, bool nonBlocking, bool isUser, ReadRequest& request) { size_t dataSize = *_length; *_length = 0; // wait until our request is first in queue status_t error; if (fReadRequests.Head() != &request) { if (nonBlocking) return B_WOULD_BLOCK; TRACE("Inode %p::%s(): wait for request %p to become the first " "request.\n", this, __FUNCTION__, &request); error = WaitForReadRequest(request); if (error != B_OK) return error; } // wait until data are available while (fBuffer.Readable() == 0) { if (nonBlocking) return B_WOULD_BLOCK; if (fActive && fWriterCount == 0) return B_OK; TRACE("Inode %p::%s(): wait for data, request %p\n", this, __FUNCTION__, &request); error = WaitForReadRequest(request); if (error != B_OK) return error; } // read as much as we can size_t toRead = fBuffer.Readable(); if (toRead > dataSize) toRead = dataSize; ssize_t bytesRead = fBuffer.Read(data, toRead, isUser); if (bytesRead < 0) return bytesRead; NotifyBytesRead(toRead); *_length = toRead; return B_OK; }
status_t Inode::Select(uint8 event, selectsync* sync, int openMode) { bool writer = true; select_sync_pool** pool; if ((openMode & O_RWMASK) == O_RDONLY) { pool = &fReadSelectSyncPool; writer = false; } else if ((openMode & O_RWMASK) == O_WRONLY) { pool = &fWriteSelectSyncPool; } else return B_NOT_ALLOWED; if (add_select_sync_pool_entry(pool, sync, event) != B_OK) return B_ERROR; // signal right away, if the condition holds already if (writer) { if ((event == B_SELECT_WRITE && (fBuffer.Writable() > 0 || fReaderCount == 0)) || (event == B_SELECT_ERROR && fReaderCount == 0)) { return notify_select_event(sync, event); } } else { if (event == B_SELECT_READ && (fBuffer.Readable() > 0 || fWriterCount == 0)) { return notify_select_event(sync, event); } } return B_OK; }
void Inode::NotifyReadDone() { // notify next reader, if there's still something to be read if (fBuffer.Readable() > 0) { if (ReadRequest* request = fReadRequests.First()) request->Notify(); } }
void Inode::NotifyBytesWritten(size_t bytes) { // notify reader, if something can be read now if (bytes > 0 && fBuffer.Readable() == bytes) { if (fReadSelectSyncPool) notify_select_event_pool(fReadSelectSyncPool, B_SELECT_READ); if (ReadRequest* request = fReadRequests.First()) request->Notify(); } }
void Inode::Dump(bool dumpData) const { kprintf("FIFO %p\n", this); kprintf(" active: %s\n", fActive ? "true" : "false"); kprintf(" readers: %" B_PRId32 "\n", fReaderCount); kprintf(" writers: %" B_PRId32 "\n", fWriterCount); if (!fReadRequests.IsEmpty()) { kprintf(" pending readers:\n"); for (ReadRequestList::ConstIterator it = fReadRequests.GetIterator(); ReadRequest* request = it.Next();) { kprintf(" %p: thread %" B_PRId32 ", cookie: %p\n", request, request->GetThread()->id, request->Cookie()); } } if (!fWriteRequests.IsEmpty()) { kprintf(" pending writers:\n"); for (WriteRequestList::ConstIterator it = fWriteRequests.GetIterator(); WriteRequest* request = it.Next();) { kprintf(" %p: thread %" B_PRId32 ", min count: %zu\n", request, request->GetThread()->id, request->MinimalWriteCount()); } } kprintf(" %zu bytes buffered\n", fBuffer.Readable()); if (dumpData && fBuffer.Readable() > 0) { struct DataProvider : BKernel::HexDumpDataProvider { DataProvider(const RingBuffer& buffer) : fBuffer(buffer), fOffset(0) { } virtual bool HasMoreData() const { return fOffset < fBuffer.Readable(); } virtual uint8 NextByte() { uint8 byte = '\0'; if (fOffset < fBuffer.Readable()) { fBuffer.Peek(fOffset, &byte, 1); fOffset++; } return byte; } virtual bool GetAddressString(char* buffer, size_t bufferSize) const { snprintf(buffer, bufferSize, " %4zx", fOffset); return true; } private: const RingBuffer& fBuffer; size_t fOffset; }; DataProvider dataProvider(fBuffer); BKernel::print_hex_dump(dataProvider, fBuffer.Readable()); } }