125eb8cd7SIngo Weinhold/*
238b150a9SIngo Weinhold * Copyright 2007-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
39061bf7eSAxel Dörfler * Copyright 2003-2010, Axel D��rfler, axeld@pinc-software.de.
425eb8cd7SIngo Weinhold * Distributed under the terms of the MIT License.
525eb8cd7SIngo Weinhold */
625eb8cd7SIngo Weinhold
79061bf7eSAxel Dörfler
89061bf7eSAxel Dörfler#include "fifo.h"
99061bf7eSAxel Dörfler
1025eb8cd7SIngo Weinhold#include <limits.h>
1125eb8cd7SIngo Weinhold#include <stdio.h>
1225eb8cd7SIngo Weinhold#include <stdlib.h>
1325eb8cd7SIngo Weinhold#include <string.h>
148019fdbaSIngo Weinhold#include <sys/ioctl.h>
1525eb8cd7SIngo Weinhold#include <sys/stat.h>
1625eb8cd7SIngo Weinhold
1725eb8cd7SIngo Weinhold#include <new>
1825eb8cd7SIngo Weinhold
1925eb8cd7SIngo Weinhold#include <KernelExport.h>
2025eb8cd7SIngo Weinhold#include <NodeMonitor.h>
2125eb8cd7SIngo Weinhold#include <Select.h>
2225eb8cd7SIngo Weinhold
2325eb8cd7SIngo Weinhold#include <condition_variable.h>
2438b150a9SIngo Weinhold#include <debug_hex_dump.h>
2525eb8cd7SIngo Weinhold#include <lock.h>
2625eb8cd7SIngo Weinhold#include <select_sync_pool.h>
278019fdbaSIngo Weinhold#include <syscall_restart.h>
2825eb8cd7SIngo Weinhold#include <team.h>
2971a49db6SIngo Weinhold#include <thread.h>
3025eb8cd7SIngo Weinhold#include <util/DoublyLinkedList.h>
3125eb8cd7SIngo Weinhold#include <util/AutoLock.h>
3225eb8cd7SIngo Weinhold#include <util/ring_buffer.h>
3325eb8cd7SIngo Weinhold#include <vfs.h>
34fb52b1f8SIngo Weinhold#include <vfs_defs.h>
35e50cf876SIngo Weinhold#include <vm/vm.h>
3625eb8cd7SIngo Weinhold
3725eb8cd7SIngo Weinhold
3825eb8cd7SIngo Weinhold//#define TRACE_FIFO
3925eb8cd7SIngo Weinhold#ifdef TRACE_FIFO
409061bf7eSAxel Dörfler#	define TRACE(x...) dprintf(x)
4125eb8cd7SIngo Weinhold#else
429061bf7eSAxel Dörfler#	define TRACE(x...)
4325eb8cd7SIngo Weinhold#endif
4425eb8cd7SIngo Weinhold
4525eb8cd7SIngo Weinhold
4625eb8cd7SIngo Weinholdnamespace fifo {
4725eb8cd7SIngo Weinhold
4881fcd71eSAxel Dörfler
4981fcd71eSAxel Dörflerstruct file_cookie;
5025eb8cd7SIngo Weinholdclass Inode;
5125eb8cd7SIngo Weinhold
5281fcd71eSAxel Dörfler
5325eb8cd7SIngo Weinholdclass RingBuffer {
541ffa5029SAxel Dörflerpublic:
551ffa5029SAxel Dörfler								RingBuffer();
561ffa5029SAxel Dörfler								~RingBuffer();
5725eb8cd7SIngo Weinhold
581ffa5029SAxel Dörfler			status_t			CreateBuffer();
591ffa5029SAxel Dörfler			void				DeleteBuffer();
6025eb8cd7SIngo Weinhold
61f170a888SIngo Weinhold			ssize_t				Write(const void* buffer, size_t length,
62f170a888SIngo Weinhold									bool isUser);
63f170a888SIngo Weinhold			ssize_t				Read(void* buffer, size_t length, bool isUser);
6438b150a9SIngo Weinhold			ssize_t				Peek(size_t offset, void* buffer,
6538b150a9SIngo Weinhold									size_t length) const;
664535495dSIngo Weinhold
671ffa5029SAxel Dörfler			size_t				Readable() const;
681ffa5029SAxel Dörfler			size_t				Writable() const;
6925eb8cd7SIngo Weinhold
701ffa5029SAxel Dörflerprivate:
711ffa5029SAxel Dörfler			struct ring_buffer*	fBuffer;
7225eb8cd7SIngo Weinhold};
7325eb8cd7SIngo Weinhold
7425eb8cd7SIngo Weinhold
7525eb8cd7SIngo Weinholdclass ReadRequest : public DoublyLinkedListLinkImpl<ReadRequest> {
761ffa5029SAxel Dörflerpublic:
771ffa5029SAxel Dörfler	ReadRequest(file_cookie* cookie)
781ffa5029SAxel Dörfler		:
791ffa5029SAxel Dörfler		fThread(thread_get_current_thread()),
801ffa5029SAxel Dörfler		fCookie(cookie),
811ffa5029SAxel Dörfler		fNotified(true)
821ffa5029SAxel Dörfler	{
831ffa5029SAxel Dörfler		B_INITIALIZE_SPINLOCK(&fLock);
841ffa5029SAxel Dörfler	}
8571a49db6SIngo Weinhold
861ffa5029SAxel Dörfler	void SetNotified(bool notified)
871ffa5029SAxel Dörfler	{
881ffa5029SAxel Dörfler		InterruptsSpinLocker _(fLock);
891ffa5029SAxel Dörfler		fNotified = notified;
901ffa5029SAxel Dörfler	}
9125eb8cd7SIngo Weinhold
921ffa5029SAxel Dörfler	void Notify(status_t status = B_OK)
931ffa5029SAxel Dörfler	{
941ffa5029SAxel Dörfler		InterruptsSpinLocker _(fLock);
951ffa5029SAxel Dörfler		TRACE("ReadRequest %p::Notify(), fNotified %d\n", this, fNotified);
96d52718a5SIngo Weinhold
971ffa5029SAxel Dörfler		if (!fNotified) {
98c8dd9f77SPawel Dziepak			thread_unblock(fThread, status);
991ffa5029SAxel Dörfler			fNotified = true;
10025eb8cd7SIngo Weinhold		}
1011ffa5029SAxel Dörfler	}
10225eb8cd7SIngo Weinhold
10338b150a9SIngo Weinhold	Thread* GetThread() const
10438b150a9SIngo Weinhold	{
10538b150a9SIngo Weinhold		return fThread;
10638b150a9SIngo Weinhold	}
10738b150a9SIngo Weinhold
1081ffa5029SAxel Dörfler	file_cookie* Cookie() const
1091ffa5029SAxel Dörfler	{
1101ffa5029SAxel Dörfler		return fCookie;
1111ffa5029SAxel Dörfler	}
11281fcd71eSAxel Dörfler
1131ffa5029SAxel Dörflerprivate:
1144535495dSIngo Weinhold	spinlock		fLock;
1154535495dSIngo Weinhold	Thread*			fThread;
1164535495dSIngo Weinhold	file_cookie*	fCookie;
1174535495dSIngo Weinhold	volatile bool	fNotified;
11825eb8cd7SIngo Weinhold};
11925eb8cd7SIngo Weinhold
12025eb8cd7SIngo Weinhold
12125eb8cd7SIngo Weinholdclass WriteRequest : public DoublyLinkedListLinkImpl<WriteRequest> {
1221ffa5029SAxel Dörflerpublic:
12338b150a9SIngo Weinhold	WriteRequest(Thread* thread, size_t minimalWriteCount)
1241ffa5029SAxel Dörfler		:
12538b150a9SIngo Weinhold		fThread(thread),
1261ffa5029SAxel Dörfler		fMinimalWriteCount(minimalWriteCount)
1271ffa5029SAxel Dörfler	{
1281ffa5029SAxel Dörfler	}
12925eb8cd7SIngo Weinhold
13038b150a9SIngo Weinhold	Thread* GetThread() const
13138b150a9SIngo Weinhold	{
13238b150a9SIngo Weinhold		return fThread;
13338b150a9SIngo Weinhold	}
13438b150a9SIngo Weinhold
1351ffa5029SAxel Dörfler	size_t MinimalWriteCount() const
1361ffa5029SAxel Dörfler	{
1371ffa5029SAxel Dörfler		return fMinimalWriteCount;
1381ffa5029SAxel Dörfler	}
13925eb8cd7SIngo Weinhold
1401ffa5029SAxel Dörflerprivate:
14138b150a9SIngo Weinhold	Thread*	fThread;
1421ffa5029SAxel Dörfler	size_t	fMinimalWriteCount;
14325eb8cd7SIngo Weinhold};
14425eb8cd7SIngo Weinhold
14525eb8cd7SIngo Weinhold
14625eb8cd7SIngo Weinholdtypedef DoublyLinkedList<ReadRequest> ReadRequestList;
14725eb8cd7SIngo Weinholdtypedef DoublyLinkedList<WriteRequest> WriteRequestList;
14825eb8cd7SIngo Weinhold
14925eb8cd7SIngo Weinhold
15025eb8cd7SIngo Weinholdclass Inode {
1511ffa5029SAxel Dörflerpublic:
1521ffa5029SAxel Dörfler								Inode();
1531ffa5029SAxel Dörfler								~Inode();
1541ffa5029SAxel Dörfler
1551ffa5029SAxel Dörfler			status_t			InitCheck();
1561ffa5029SAxel Dörfler
1571ffa5029SAxel Dörfler			bool				IsActive() const { return fActive; }
1581ffa5029SAxel Dörfler			timespec			CreationTime() const { return fCreationTime; }
1591ffa5029SAxel Dörfler			void				SetCreationTime(timespec creationTime)
1601ffa5029SAxel Dörfler									{ fCreationTime = creationTime; }
1611ffa5029SAxel Dörfler			timespec			ModificationTime() const
1621ffa5029SAxel Dörfler									{ return fModificationTime; }
1631ffa5029SAxel Dörfler			void				SetModificationTime(timespec modificationTime)
1641ffa5029SAxel Dörfler									{ fModificationTime = modificationTime; }
1654535495dSIngo Weinhold
1661ffa5029SAxel Dörfler			mutex*				RequestLock() { return &fRequestLock; }
1674535495dSIngo Weinhold
1681ffa5029SAxel Dörfler			status_t			WriteDataToBuffer(const void* data,
169f170a888SIngo Weinhold									size_t* _length, bool nonBlocking,
170f170a888SIngo Weinhold									bool isUser);
1711ffa5029SAxel Dörfler			status_t			ReadDataFromBuffer(void* data, size_t* _length,
172f170a888SIngo Weinhold									bool nonBlocking, bool isUser,
173f170a888SIngo Weinhold									ReadRequest& request);
1741ffa5029SAxel Dörfler			size_t				BytesAvailable() const
1751ffa5029SAxel Dörfler									{ return fBuffer.Readable(); }
1761ffa5029SAxel Dörfler			size_t				BytesWritable() const
1771ffa5029SAxel Dörfler									{ return fBuffer.Writable(); }
1784535495dSIngo Weinhold
1791ffa5029SAxel Dörfler			void				AddReadRequest(ReadRequest& request);
1801ffa5029SAxel Dörfler			void				RemoveReadRequest(ReadRequest& request);
1811ffa5029SAxel Dörfler			status_t			WaitForReadRequest(ReadRequest& request);
1824535495dSIngo Weinhold
1831ffa5029SAxel Dörfler			void				NotifyBytesRead(size_t bytes);
1841ffa5029SAxel Dörfler			void				NotifyReadDone();
1851ffa5029SAxel Dörfler			void				NotifyBytesWritten(size_t bytes);
1861ffa5029SAxel Dörfler			void				NotifyEndClosed(bool writer);
1874535495dSIngo Weinhold
1881ffa5029SAxel Dörfler			void				Open(int openMode);
189fd0bfd55SIngo Weinhold			void				Close(file_cookie* cookie);
1901ffa5029SAxel Dörfler			int32				ReaderCount() const { return fReaderCount; }
1911ffa5029SAxel Dörfler			int32				WriterCount() const { return fWriterCount; }
1924535495dSIngo Weinhold
1931ffa5029SAxel Dörfler			status_t			Select(uint8 event, selectsync* sync,
1941ffa5029SAxel Dörfler									int openMode);
1951ffa5029SAxel Dörfler			status_t			Deselect(uint8 event, selectsync* sync,
1961ffa5029SAxel Dörfler									int openMode);
19725eb8cd7SIngo Weinhold
19838b150a9SIngo Weinhold			void				Dump(bool dumpData) const;
19938b150a9SIngo Weinhold	static	int					Dump(int argc, char** argv);
20038b150a9SIngo Weinhold
2011ffa5029SAxel Dörflerprivate:
2021ffa5029SAxel Dörfler			timespec			fCreationTime;
2031ffa5029SAxel Dörfler			timespec			fModificationTime;
2044535495dSIngo Weinhold
2051ffa5029SAxel Dörfler			RingBuffer			fBuffer;
2064535495dSIngo Weinhold
2071ffa5029SAxel Dörfler			ReadRequestList		fReadRequests;
2081ffa5029SAxel Dörfler			WriteRequestList	fWriteRequests;
2094535495dSIngo Weinhold
2101ffa5029SAxel Dörfler			mutex				fRequestLock;
2114535495dSIngo Weinhold
2121ffa5029SAxel Dörfler			ConditionVariable	fWriteCondition;
2134535495dSIngo Weinhold
2141ffa5029SAxel Dörfler			int32				fReaderCount;
2151ffa5029SAxel Dörfler			int32				fWriterCount;
2161ffa5029SAxel Dörfler			bool				fActive;
2174535495dSIngo Weinhold
2181ffa5029SAxel Dörfler			select_sync_pool*	fReadSelectSyncPool;
2191ffa5029SAxel Dörfler			select_sync_pool*	fWriteSelectSyncPool;
22025eb8cd7SIngo Weinhold};
22125eb8cd7SIngo Weinhold
22225eb8cd7SIngo Weinhold
22325eb8cd7SIngo Weinholdclass FIFOInode : public Inode {
22425eb8cd7SIngo Weinholdpublic:
22525eb8cd7SIngo Weinhold	FIFOInode(fs_vnode* vnode)
22625eb8cd7SIngo Weinhold		:
22725eb8cd7SIngo Weinhold		Inode(),
22825eb8cd7SIngo Weinhold		fSuperVnode(*vnode)
22925eb8cd7SIngo Weinhold	{
23025eb8cd7SIngo Weinhold	}
23125eb8cd7SIngo Weinhold
23225eb8cd7SIngo Weinhold	fs_vnode*	SuperVnode() { return &fSuperVnode; }
23325eb8cd7SIngo Weinhold
23425eb8cd7SIngo Weinholdprivate:
23525eb8cd7SIngo Weinhold	fs_vnode	fSuperVnode;
23625eb8cd7SIngo Weinhold};
23725eb8cd7SIngo Weinhold
23825eb8cd7SIngo Weinhold
23925eb8cd7SIngo Weinholdstruct file_cookie {
240fd0bfd55SIngo Weinhold	int	open_mode;
241fd0bfd55SIngo Weinhold			// guarded by Inode::fRequestLock
2428019fdbaSIngo Weinhold
2438019fdbaSIngo Weinhold	void SetNonBlocking(bool nonBlocking)
2448019fdbaSIngo Weinhold	{
2458019fdbaSIngo Weinhold		if (nonBlocking)
2468019fdbaSIngo Weinhold			open_mode |= O_NONBLOCK;
2478019fdbaSIngo Weinhold		else
2488019fdbaSIngo Weinhold			open_mode &= ~(int)O_NONBLOCK;
2498019fdbaSIngo Weinhold	}
25025eb8cd7SIngo Weinhold};
25125eb8cd7SIngo Weinhold
25225eb8cd7SIngo Weinhold
25381fcd71eSAxel Dörfler// #pragma mark -
25425eb8cd7SIngo Weinhold
25525eb8cd7SIngo Weinhold
25625eb8cd7SIngo WeinholdRingBuffer::RingBuffer()
2571ffa5029SAxel Dörfler	:
2581ffa5029SAxel Dörfler	fBuffer(NULL)
25925eb8cd7SIngo Weinhold{
26025eb8cd7SIngo Weinhold}
26125eb8cd7SIngo Weinhold
26225eb8cd7SIngo Weinhold
26325eb8cd7SIngo WeinholdRingBuffer::~RingBuffer()
26425eb8cd7SIngo Weinhold{
26525eb8cd7SIngo Weinhold	DeleteBuffer();
26625eb8cd7SIngo Weinhold}
26725eb8cd7SIngo Weinhold
26825eb8cd7SIngo Weinhold
26925eb8cd7SIngo Weinholdstatus_t
27025eb8cd7SIngo WeinholdRingBuffer::CreateBuffer()
27125eb8cd7SIngo Weinhold{
27225eb8cd7SIngo Weinhold	if (fBuffer != NULL)
27325eb8cd7SIngo Weinhold		return B_OK;
27425eb8cd7SIngo Weinhold
275fb52b1f8SIngo Weinhold	fBuffer = create_ring_buffer(VFS_FIFO_BUFFER_CAPACITY);
2761ffa5029SAxel Dörfler	return fBuffer != NULL ? B_OK : B_NO_MEMORY;
27725eb8cd7SIngo Weinhold}
27825eb8cd7SIngo Weinhold
27925eb8cd7SIngo Weinhold
28025eb8cd7SIngo Weinholdvoid
28125eb8cd7SIngo WeinholdRingBuffer::DeleteBuffer()
28225eb8cd7SIngo Weinhold{
28325eb8cd7SIngo Weinhold	if (fBuffer != NULL) {
28425eb8cd7SIngo Weinhold		delete_ring_buffer(fBuffer);
28525eb8cd7SIngo Weinhold		fBuffer = NULL;
28625eb8cd7SIngo Weinhold	}
28725eb8cd7SIngo Weinhold}
28825eb8cd7SIngo Weinhold
28925eb8cd7SIngo Weinhold
290334ae3c7SIngo Weinholdinline ssize_t
291f170a888SIngo WeinholdRingBuffer::Write(const void* buffer, size_t length, bool isUser)
29225eb8cd7SIngo Weinhold{
29325eb8cd7SIngo Weinhold	if (fBuffer == NULL)
29425eb8cd7SIngo Weinhold		return B_NO_MEMORY;
295f170a888SIngo Weinhold	if (isUser && !IS_USER_ADDRESS(buffer))
296f170a888SIngo Weinhold		return B_BAD_ADDRESS;
29725eb8cd7SIngo Weinhold
298f170a888SIngo Weinhold	return isUser
299f170a888SIngo Weinhold		? ring_buffer_user_write(fBuffer, (const uint8*)buffer, length)
300f170a888SIngo Weinhold		: ring_buffer_write(fBuffer, (const uint8*)buffer, length);
30125eb8cd7SIngo Weinhold}
30225eb8cd7SIngo Weinhold
30325eb8cd7SIngo Weinhold
304334ae3c7SIngo Weinholdinline ssize_t
305f170a888SIngo WeinholdRingBuffer::Read(void* buffer, size_t length, bool isUser)
30625eb8cd7SIngo Weinhold{
30725eb8cd7SIngo Weinhold	if (fBuffer == NULL)
30825eb8cd7SIngo Weinhold		return B_NO_MEMORY;
309f170a888SIngo Weinhold	if (isUser && !IS_USER_ADDRESS(buffer))
310f170a888SIngo Weinhold		return B_BAD_ADDRESS;
31125eb8cd7SIngo Weinhold
312f170a888SIngo Weinhold	return isUser
313f170a888SIngo Weinhold		? ring_buffer_user_read(fBuffer, (uint8*)buffer, length)
314f170a888SIngo Weinhold		: ring_buffer_read(fBuffer, (uint8*)buffer, length);
31525eb8cd7SIngo Weinhold}
31625eb8cd7SIngo Weinhold
31725eb8cd7SIngo Weinhold
31838b150a9SIngo Weinholdinline ssize_t
31938b150a9SIngo WeinholdRingBuffer::Peek(size_t offset, void* buffer, size_t length) const
32038b150a9SIngo Weinhold{
32138b150a9SIngo Weinhold	if (fBuffer == NULL)
32238b150a9SIngo Weinhold		return B_NO_MEMORY;
32338b150a9SIngo Weinhold
32438b150a9SIngo Weinhold	return ring_buffer_peek(fBuffer, offset, (uint8*)buffer, length);
32538b150a9SIngo Weinhold}
32638b150a9SIngo Weinhold
32738b150a9SIngo Weinhold
32825eb8cd7SIngo Weinholdinline size_t
32925eb8cd7SIngo WeinholdRingBuffer::Readable() const
33025eb8cd7SIngo Weinhold{
3311ffa5029SAxel Dörfler	return fBuffer != NULL ? ring_buffer_readable(fBuffer) : 0;
33225eb8cd7SIngo Weinhold}
33325eb8cd7SIngo Weinhold
33425eb8cd7SIngo Weinhold
33525eb8cd7SIngo Weinholdinline size_t
33625eb8cd7SIngo WeinholdRingBuffer::Writable() const
33725eb8cd7SIngo Weinhold{
3381ffa5029SAxel Dörfler	return fBuffer != NULL ? ring_buffer_writable(fBuffer) : 0;
33925eb8cd7SIngo Weinhold}
34025eb8cd7SIngo Weinhold
34125eb8cd7SIngo Weinhold
34225eb8cd7SIngo Weinhold//	#pragma mark -
34325eb8cd7SIngo Weinhold
34425eb8cd7SIngo Weinhold
34525eb8cd7SIngo WeinholdInode::Inode()
34625eb8cd7SIngo Weinhold	:
34725eb8cd7SIngo Weinhold	fReadRequests(),
34825eb8cd7SIngo Weinhold	fWriteRequests(),
34925eb8cd7SIngo Weinhold	fReaderCount(0),
35025eb8cd7SIngo Weinhold	fWriterCount(0),
35125eb8cd7SIngo Weinhold	fActive(false),
35225eb8cd7SIngo Weinhold	fReadSelectSyncPool(NULL),
35325eb8cd7SIngo Weinhold	fWriteSelectSyncPool(NULL)
35425eb8cd7SIngo Weinhold{
35525eb8cd7SIngo Weinhold	fWriteCondition.Publish(this, "pipe");
356adf376c9SAxel Dörfler	mutex_init(&fRequestLock, "pipe request");
35725eb8cd7SIngo Weinhold
358fa00207cSAxel Dörfler	bigtime_t time = real_time_clock();
359fa00207cSAxel Dörfler	fModificationTime.tv_sec = time / 1000000;
360fa00207cSAxel Dörfler	fModificationTime.tv_nsec = (time % 1000000) * 1000;
361fa00207cSAxel Dörfler	fCreationTime = fModificationTime;
36225eb8cd7SIngo Weinhold}
36325eb8cd7SIngo Weinhold
36425eb8cd7SIngo Weinhold
36525eb8cd7SIngo WeinholdInode::~Inode()
36625eb8cd7SIngo Weinhold{
36725eb8cd7SIngo Weinhold	fWriteCondition.Unpublish();
368adf376c9SAxel Dörfler	mutex_destroy(&fRequestLock);
36925eb8cd7SIngo Weinhold}
37025eb8cd7SIngo Weinhold
37125eb8cd7SIngo Weinhold
372e6bd90c5SIngo Weinholdstatus_t
37325eb8cd7SIngo WeinholdInode::InitCheck()
37425eb8cd7SIngo Weinhold{
37525eb8cd7SIngo Weinhold	return B_OK;
37625eb8cd7SIngo Weinhold}
37725eb8cd7SIngo Weinhold
37825eb8cd7SIngo Weinhold
379adf376c9SAxel Dörfler/*!	Writes the specified data bytes to the inode's ring buffer. The
38025eb8cd7SIngo Weinhold	request lock must be held when calling this method.
38125eb8cd7SIngo Weinhold	Notifies readers if necessary, so that blocking readers will get started.
38225eb8cd7SIngo Weinhold	Returns B_OK for success, B_BAD_ADDRESS if copying from the buffer failed,
38325eb8cd7SIngo Weinhold	and various semaphore errors (like B_WOULD_BLOCK in non-blocking mode). If
38425eb8cd7SIngo Weinhold	the returned length is > 0, the returned error code can be ignored.
38525eb8cd7SIngo Weinhold*/
38625eb8cd7SIngo Weinholdstatus_t
387f170a888SIngo WeinholdInode::WriteDataToBuffer(const void* _data, size_t* _length, bool nonBlocking,
388f170a888SIngo Weinhold	bool isUser)
38925eb8cd7SIngo Weinhold{
39025eb8cd7SIngo Weinhold	const uint8* data = (const uint8*)_data;
39125eb8cd7SIngo Weinhold	size_t dataSize = *_length;
39225eb8cd7SIngo Weinhold	size_t& written = *_length;
39325eb8cd7SIngo Weinhold	written = 0;
39425eb8cd7SIngo Weinhold
3959061bf7eSAxel Dörfler	TRACE("Inode %p::WriteDataToBuffer(data = %p, bytes = %zu)\n", this, data,
3969061bf7eSAxel Dörfler		dataSize);
39725eb8cd7SIngo Weinhold
398fb52b1f8SIngo Weinhold	// A request up to VFS_FIFO_ATOMIC_WRITE_SIZE bytes shall not be
39925eb8cd7SIngo Weinhold	// interleaved with other writer's data.
40025eb8cd7SIngo Weinhold	size_t minToWrite = 1;
401fb52b1f8SIngo Weinhold	if (dataSize <= VFS_FIFO_ATOMIC_WRITE_SIZE)
40225eb8cd7SIngo Weinhold		minToWrite = dataSize;
40325eb8cd7SIngo Weinhold
40425eb8cd7SIngo Weinhold	while (dataSize > 0) {
40525eb8cd7SIngo Weinhold		// Wait until enough space in the buffer is available.
40625eb8cd7SIngo Weinhold		while (!fActive
407c33667d4SMichael Lotz				|| (fBuffer.Writable() < minToWrite && fReaderCount > 0)) {
40825eb8cd7SIngo Weinhold			if (nonBlocking)
40925eb8cd7SIngo Weinhold				return B_WOULD_BLOCK;
41025eb8cd7SIngo Weinhold
4116cef245eSIngo Weinhold			ConditionVariableEntry entry;
412fbe0c27aSIngo Weinhold			entry.Add(this);
41325eb8cd7SIngo Weinhold
41438b150a9SIngo Weinhold			WriteRequest request(thread_get_current_thread(), minToWrite);
41525eb8cd7SIngo Weinhold			fWriteRequests.Add(&request);
41625eb8cd7SIngo Weinhold
417adf376c9SAxel Dörfler			mutex_unlock(&fRequestLock);
418fbe0c27aSIngo Weinhold			status_t status = entry.Wait(B_CAN_INTERRUPT);
419adf376c9SAxel Dörfler			mutex_lock(&fRequestLock);
42025eb8cd7SIngo Weinhold
42125eb8cd7SIngo Weinhold			fWriteRequests.Remove(&request);
42225eb8cd7SIngo Weinhold
42325eb8cd7SIngo Weinhold			if (status != B_OK)
42425eb8cd7SIngo Weinhold				return status;
42525eb8cd7SIngo Weinhold		}
42625eb8cd7SIngo Weinhold
42725eb8cd7SIngo Weinhold		// write only as long as there are readers left
42881fcd71eSAxel Dörfler		if (fActive && fReaderCount == 0) {
42925eb8cd7SIngo Weinhold			if (written == 0)
43025eb8cd7SIngo Weinhold				send_signal(find_thread(NULL), SIGPIPE);
43125eb8cd7SIngo Weinhold			return EPIPE;
43225eb8cd7SIngo Weinhold		}
43325eb8cd7SIngo Weinhold
43425eb8cd7SIngo Weinhold		// write as much as we can
43525eb8cd7SIngo Weinhold
43625eb8cd7SIngo Weinhold		size_t toWrite = (fActive ? fBuffer.Writable() : 0);
43725eb8cd7SIngo Weinhold		if (toWrite > dataSize)
43825eb8cd7SIngo Weinhold			toWrite = dataSize;
43925eb8cd7SIngo Weinhold
440f170a888SIngo Weinhold		if (toWrite > 0) {
441f170a888SIngo Weinhold			ssize_t bytesWritten = fBuffer.Write(data, toWrite, isUser);
442f170a888SIngo Weinhold			if (bytesWritten < 0)
443f170a888SIngo Weinhold				return bytesWritten;
444f170a888SIngo Weinhold		}
44525eb8cd7SIngo Weinhold
44625eb8cd7SIngo Weinhold		data += toWrite;
44725eb8cd7SIngo Weinhold		dataSize -= toWrite;
44825eb8cd7SIngo Weinhold		written += toWrite;
44925eb8cd7SIngo Weinhold
45025eb8cd7SIngo Weinhold		NotifyBytesWritten(toWrite);
45125eb8cd7SIngo Weinhold	}
45225eb8cd7SIngo Weinhold
45325eb8cd7SIngo Weinhold	return B_OK;
45425eb8cd7SIngo Weinhold}
45525eb8cd7SIngo Weinhold
45625eb8cd7SIngo Weinhold
45725eb8cd7SIngo Weinholdstatus_t
4581ffa5029SAxel DörflerInode::ReadDataFromBuffer(void* data, size_t* _length, bool nonBlocking,
459f170a888SIngo Weinhold	bool isUser, ReadRequest& request)
46025eb8cd7SIngo Weinhold{
46125eb8cd7SIngo Weinhold	size_t dataSize = *_length;
46225eb8cd7SIngo Weinhold	*_length = 0;
46325eb8cd7SIngo Weinhold
46425eb8cd7SIngo Weinhold	// wait until our request is first in queue
46525eb8cd7SIngo Weinhold	status_t error;
46625eb8cd7SIngo Weinhold	if (fReadRequests.Head() != &request) {
46725eb8cd7SIngo Weinhold		if (nonBlocking)
46825eb8cd7SIngo Weinhold			return B_WOULD_BLOCK;
46925eb8cd7SIngo Weinhold
4709061bf7eSAxel Dörfler		TRACE("Inode %p::%s(): wait for request %p to become the first "
4719061bf7eSAxel Dörfler			"request.\n", this, __FUNCTION__, &request);
4729061bf7eSAxel Dörfler
47325eb8cd7SIngo Weinhold		error = WaitForReadRequest(request);
47425eb8cd7SIngo Weinhold		if (error != B_OK)
47525eb8cd7SIngo Weinhold			return error;
47625eb8cd7SIngo Weinhold	}
47725eb8cd7SIngo Weinhold
47825eb8cd7SIngo Weinhold	// wait until data are available
47925eb8cd7SIngo Weinhold	while (fBuffer.Readable() == 0) {
48025eb8cd7SIngo Weinhold		if (nonBlocking)
48125eb8cd7SIngo Weinhold			return B_WOULD_BLOCK;
48225eb8cd7SIngo Weinhold
483dac5d7feSAxel Dörfler		if (fActive && fWriterCount == 0)
48425eb8cd7SIngo Weinhold			return B_OK;
48525eb8cd7SIngo Weinhold
4869061bf7eSAxel Dörfler		TRACE("Inode %p::%s(): wait for data, request %p\n", this, __FUNCTION__,
4879061bf7eSAxel Dörfler			&request);
4889061bf7eSAxel Dörfler
48925eb8cd7SIngo Weinhold		error = WaitForReadRequest(request);
49025eb8cd7SIngo Weinhold		if (error != B_OK)
49125eb8cd7SIngo Weinhold			return error;
49225eb8cd7SIngo Weinhold	}
49325eb8cd7SIngo Weinhold
49425eb8cd7SIngo Weinhold	// read as much as we can
49525eb8cd7SIngo Weinhold	size_t toRead = fBuffer.Readable();
49625eb8cd7SIngo Weinhold	if (toRead > dataSize)
49725eb8cd7SIngo Weinhold		toRead = dataSize;
49825eb8cd7SIngo Weinhold
499f170a888SIngo Weinhold	ssize_t bytesRead = fBuffer.Read(data, toRead, isUser);
500f170a888SIngo Weinhold	if (bytesRead < 0)
501f170a888SIngo Weinhold		return bytesRead;
50225eb8cd7SIngo Weinhold
50325eb8cd7SIngo Weinhold	NotifyBytesRead(toRead);
50425eb8cd7SIngo Weinhold
50525eb8cd7SIngo Weinhold	*_length = toRead;
50625eb8cd7SIngo Weinhold
50725eb8cd7SIngo Weinhold	return B_OK;
50825eb8cd7SIngo Weinhold}
50925eb8cd7SIngo Weinhold
51025eb8cd7SIngo Weinhold
51125eb8cd7SIngo Weinholdvoid
5121ffa5029SAxel DörflerInode::AddReadRequest(ReadRequest& request)
51325eb8cd7SIngo Weinhold{
51425eb8cd7SIngo Weinhold	fReadRequests.Add(&request);
51525eb8cd7SIngo Weinhold}
51625eb8cd7SIngo Weinhold
51725eb8cd7SIngo Weinhold
51825eb8cd7SIngo Weinholdvoid
5191ffa5029SAxel DörflerInode::RemoveReadRequest(ReadRequest& request)
52025eb8cd7SIngo Weinhold{
52125eb8cd7SIngo Weinhold	fReadRequests.Remove(&request);
52225eb8cd7SIngo Weinhold}
52325eb8cd7SIngo Weinhold
52425eb8cd7SIngo Weinhold
52525eb8cd7SIngo Weinholdstatus_t
5261ffa5029SAxel DörflerInode::WaitForReadRequest(ReadRequest& request)
52725eb8cd7SIngo Weinhold{
52825eb8cd7SIngo Weinhold	// add the entry to wait on
52971a49db6SIngo Weinhold	thread_prepare_to_block(thread_get_current_thread(), B_CAN_INTERRUPT,
53071a49db6SIngo Weinhold		THREAD_BLOCK_TYPE_OTHER, "fifo read request");
53125eb8cd7SIngo Weinhold
532d52718a5SIngo Weinhold	request.SetNotified(false);
533d52718a5SIngo Weinhold
53425eb8cd7SIngo Weinhold	// wait
535adf376c9SAxel Dörfler	mutex_unlock(&fRequestLock);
53671a49db6SIngo Weinhold	status_t status = thread_block();
537d52718a5SIngo Weinhold
538d52718a5SIngo Weinhold	// Before going to lock again, we need to make sure no one tries to
539d52718a5SIngo Weinhold	// unblock us. Otherwise that would screw with mutex_lock().
540d52718a5SIngo Weinhold	request.SetNotified(true);
541d52718a5SIngo Weinhold
542adf376c9SAxel Dörfler	mutex_lock(&fRequestLock);
54325eb8cd7SIngo Weinhold
54425eb8cd7SIngo Weinhold	return status;
54525eb8cd7SIngo Weinhold}
54625eb8cd7SIngo Weinhold
54725eb8cd7SIngo Weinhold
54825eb8cd7SIngo Weinholdvoid
54925eb8cd7SIngo WeinholdInode::NotifyBytesRead(size_t bytes)
55025eb8cd7SIngo Weinhold{
55125eb8cd7SIngo Weinhold	// notify writer, if something can be written now
55225eb8cd7SIngo Weinhold	size_t writable = fBuffer.Writable();
55325eb8cd7SIngo Weinhold	if (bytes > 0) {
55425eb8cd7SIngo Weinhold		// notify select()ors only, if nothing was writable before
55525eb8cd7SIngo Weinhold		if (writable == bytes) {
55625eb8cd7SIngo Weinhold			if (fWriteSelectSyncPool)
55725eb8cd7SIngo Weinhold				notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_WRITE);
55825eb8cd7SIngo Weinhold		}
55925eb8cd7SIngo Weinhold
56025eb8cd7SIngo Weinhold		// If any of the waiting writers has a minimal write count that has
56125eb8cd7SIngo Weinhold		// now become satisfied, we notify all of them (condition variables
56225eb8cd7SIngo Weinhold		// don't support doing that selectively).
5631ffa5029SAxel Dörfler		WriteRequest* request;
56425eb8cd7SIngo Weinhold		WriteRequestList::Iterator iterator = fWriteRequests.GetIterator();
56525eb8cd7SIngo Weinhold		while ((request = iterator.Next()) != NULL) {
56625eb8cd7SIngo Weinhold			size_t minWriteCount = request->MinimalWriteCount();
56725eb8cd7SIngo Weinhold			if (minWriteCount > 0 && minWriteCount <= writable
56825eb8cd7SIngo Weinhold					&& minWriteCount > writable - bytes) {
56925eb8cd7SIngo Weinhold				fWriteCondition.NotifyAll();
57025eb8cd7SIngo Weinhold				break;
57125eb8cd7SIngo Weinhold			}
57225eb8cd7SIngo Weinhold		}
57325eb8cd7SIngo Weinhold	}
57425eb8cd7SIngo Weinhold}
57525eb8cd7SIngo Weinhold
57625eb8cd7SIngo Weinhold
57725eb8cd7SIngo Weinholdvoid
57825eb8cd7SIngo WeinholdInode::NotifyReadDone()
57925eb8cd7SIngo Weinhold{
58025eb8cd7SIngo Weinhold	// notify next reader, if there's still something to be read
58125eb8cd7SIngo Weinhold	if (fBuffer.Readable() > 0) {
58225eb8cd7SIngo Weinhold		if (ReadRequest* request = fReadRequests.First())
58325eb8cd7SIngo Weinhold			request->Notify();
58425eb8cd7SIngo Weinhold	}
58525eb8cd7SIngo Weinhold}
58625eb8cd7SIngo Weinhold
58725eb8cd7SIngo Weinhold
58825eb8cd7SIngo Weinholdvoid
58925eb8cd7SIngo WeinholdInode::NotifyBytesWritten(size_t bytes)
59025eb8cd7SIngo Weinhold{
59125eb8cd7SIngo Weinhold	// notify reader, if something can be read now
59225eb8cd7SIngo Weinhold	if (bytes > 0 && fBuffer.Readable() == bytes) {
59325eb8cd7SIngo Weinhold		if (fReadSelectSyncPool)
59425eb8cd7SIngo Weinhold			notify_select_event_pool(fReadSelectSyncPool, B_SELECT_READ);
59525eb8cd7SIngo Weinhold
59625eb8cd7SIngo Weinhold		if (ReadRequest* request = fReadRequests.First())
59725eb8cd7SIngo Weinhold			request->Notify();
59825eb8cd7SIngo Weinhold	}
59925eb8cd7SIngo Weinhold}
60025eb8cd7SIngo Weinhold
60125eb8cd7SIngo Weinhold
60225eb8cd7SIngo Weinholdvoid
60325eb8cd7SIngo WeinholdInode::NotifyEndClosed(bool writer)
60425eb8cd7SIngo Weinhold{
6059061bf7eSAxel Dörfler	TRACE("Inode %p::%s(%s)\n", this, __FUNCTION__,
6069061bf7eSAxel Dörfler		writer ? "writer" : "reader");
6079061bf7eSAxel Dörfler
60825eb8cd7SIngo Weinhold	if (writer) {
60925eb8cd7SIngo Weinhold		// Our last writer has been closed; if the pipe
61025eb8cd7SIngo Weinhold		// contains no data, unlock all waiting readers
6119061bf7eSAxel Dörfler		TRACE("  buffer readable: %zu\n", fBuffer.Readable());
61225eb8cd7SIngo Weinhold		if (fBuffer.Readable() == 0) {
61325eb8cd7SIngo Weinhold			ReadRequestList::Iterator iterator = fReadRequests.GetIterator();
6149061bf7eSAxel Dörfler			while (ReadRequest* request = iterator.Next())
61525eb8cd7SIngo Weinhold				request->Notify();
61625eb8cd7SIngo Weinhold
61725eb8cd7SIngo Weinhold			if (fReadSelectSyncPool)
61865abebfaSPhilippe Houdoin				notify_select_event_pool(fReadSelectSyncPool, B_SELECT_READ);
61925eb8cd7SIngo Weinhold		}
62025eb8cd7SIngo Weinhold	} else {
62125eb8cd7SIngo Weinhold		// Last reader is gone. Wake up all writers.
62225eb8cd7SIngo Weinhold		fWriteCondition.NotifyAll();
62325eb8cd7SIngo Weinhold
62425eb8cd7SIngo Weinhold		if (fWriteSelectSyncPool) {
62565abebfaSPhilippe Houdoin			notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_WRITE);
6262a081b42SPhilippe Houdoin			notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_ERROR);
62725eb8cd7SIngo Weinhold		}
62825eb8cd7SIngo Weinhold	}
62925eb8cd7SIngo Weinhold}
63025eb8cd7SIngo Weinhold
63125eb8cd7SIngo Weinhold
63225eb8cd7SIngo Weinholdvoid
63325eb8cd7SIngo WeinholdInode::Open(int openMode)
63425eb8cd7SIngo Weinhold{
635adf376c9SAxel Dörfler	MutexLocker locker(RequestLock());
63625eb8cd7SIngo Weinhold
63725eb8cd7SIngo Weinhold	if ((openMode & O_ACCMODE) == O_WRONLY)
63825eb8cd7SIngo Weinhold		fWriterCount++;
63925eb8cd7SIngo Weinhold
64025eb8cd7SIngo Weinhold	if ((openMode & O_ACCMODE) == O_RDONLY || (openMode & O_ACCMODE) == O_RDWR)
64125eb8cd7SIngo Weinhold		fReaderCount++;
64225eb8cd7SIngo Weinhold
64325eb8cd7SIngo Weinhold	if (fReaderCount > 0 && fWriterCount > 0) {
6449061bf7eSAxel Dörfler		TRACE("Inode %p::Open(): fifo becomes active\n", this);
64525eb8cd7SIngo Weinhold		fBuffer.CreateBuffer();
64625eb8cd7SIngo Weinhold		fActive = true;
64725eb8cd7SIngo Weinhold
64825eb8cd7SIngo Weinhold		// notify all waiting writers that they can start
64925eb8cd7SIngo Weinhold		if (fWriteSelectSyncPool)
65025eb8cd7SIngo Weinhold			notify_select_event_pool(fWriteSelectSyncPool, B_SELECT_WRITE);
65125eb8cd7SIngo Weinhold		fWriteCondition.NotifyAll();
65225eb8cd7SIngo Weinhold	}
65325eb8cd7SIngo Weinhold}
65425eb8cd7SIngo Weinhold
65525eb8cd7SIngo Weinhold
65625eb8cd7SIngo Weinholdvoid
657fd0bfd55SIngo WeinholdInode::Close(file_cookie* cookie)
65825eb8cd7SIngo Weinhold{
6599061bf7eSAxel Dörfler	TRACE("Inode %p::Close(openMode = %d)\n", this, openMode);
66025eb8cd7SIngo Weinhold
661adf376c9SAxel Dörfler	MutexLocker locker(RequestLock());
66225eb8cd7SIngo Weinhold
663fd0bfd55SIngo Weinhold	int openMode = cookie->open_mode;
664fd0bfd55SIngo Weinhold
66581fcd71eSAxel Dörfler	// Notify all currently reading file descriptors
66681fcd71eSAxel Dörfler	ReadRequestList::Iterator iterator = fReadRequests.GetIterator();
66781fcd71eSAxel Dörfler	while (ReadRequest* request = iterator.Next()) {
66881fcd71eSAxel Dörfler		if (request->Cookie() == cookie)
66981fcd71eSAxel Dörfler			request->Notify(B_FILE_ERROR);
67081fcd71eSAxel Dörfler	}
67181fcd71eSAxel Dörfler
67225eb8cd7SIngo Weinhold	if ((openMode & O_ACCMODE) == O_WRONLY && --fWriterCount == 0)
67325eb8cd7SIngo Weinhold		NotifyEndClosed(true);
67425eb8cd7SIngo Weinhold
6759061bf7eSAxel Dörfler	if ((openMode & O_ACCMODE) == O_RDONLY
6769061bf7eSAxel Dörfler		|| (openMode & O_ACCMODE) == O_RDWR) {
67725eb8cd7SIngo Weinhold		if (--fReaderCount == 0)
67825eb8cd7SIngo Weinhold			NotifyEndClosed(false);
67925eb8cd7SIngo Weinhold	}
68025eb8cd7SIngo Weinhold
681dac5d7feSAxel Dörfler	if (fWriterCount == 0) {
682dac5d7feSAxel Dörfler		// Notify any still reading writers to stop
683dac5d7feSAxel Dörfler		// TODO: This only works reliable if there is only one writer - we could
684dac5d7feSAxel Dörfler		// do the same thing done for the read requests.
685dac5d7feSAxel Dörfler		fWriteCondition.NotifyAll(B_FILE_ERROR);
686dac5d7feSAxel Dörfler	}
687dac5d7feSAxel Dörfler
68825eb8cd7SIngo Weinhold	if (fReaderCount == 0 && fWriterCount == 0) {
68925eb8cd7SIngo Weinhold		fActive = false;
69025eb8cd7SIngo Weinhold		fBuffer.DeleteBuffer();
69125eb8cd7SIngo Weinhold	}
69225eb8cd7SIngo Weinhold}
69325eb8cd7SIngo Weinhold
69425eb8cd7SIngo Weinhold
69525eb8cd7SIngo Weinholdstatus_t
6961ffa5029SAxel DörflerInode::Select(uint8 event, selectsync* sync, int openMode)
69725eb8cd7SIngo Weinhold{
69825eb8cd7SIngo Weinhold	bool writer = true;
69925eb8cd7SIngo Weinhold	select_sync_pool** pool;
70025eb8cd7SIngo Weinhold	if ((openMode & O_RWMASK) == O_RDONLY) {
70125eb8cd7SIngo Weinhold		pool = &fReadSelectSyncPool;
70225eb8cd7SIngo Weinhold		writer = false;
70325eb8cd7SIngo Weinhold	} else if ((openMode & O_RWMASK) == O_WRONLY) {
70425eb8cd7SIngo Weinhold		pool = &fWriteSelectSyncPool;
70525eb8cd7SIngo Weinhold	} else
70625eb8cd7SIngo Weinhold		return B_NOT_ALLOWED;
70725eb8cd7SIngo Weinhold
70825eb8cd7SIngo Weinhold	if (add_select_sync_pool_entry(pool, sync, event) != B_OK)
70925eb8cd7SIngo Weinhold		return B_ERROR;
71025eb8cd7SIngo Weinhold
71125eb8cd7SIngo Weinhold	// signal right away, if the condition holds already
71225eb8cd7SIngo Weinhold	if (writer) {
7132a081b42SPhilippe Houdoin		if ((event == B_SELECT_WRITE
7142a081b42SPhilippe Houdoin				&& (fBuffer.Writable() > 0 || fReaderCount == 0))
7152a081b42SPhilippe Houdoin			|| (event == B_SELECT_ERROR && fReaderCount == 0)) {
71625eb8cd7SIngo Weinhold			return notify_select_event(sync, event);
71765abebfaSPhilippe Houdoin		}
71825eb8cd7SIngo Weinhold	} else {
7192a081b42SPhilippe Houdoin		if (event == B_SELECT_READ
7202a081b42SPhilippe Houdoin				&& (fBuffer.Readable() > 0 || fWriterCount == 0)) {
72125eb8cd7SIngo Weinhold			return notify_select_event(sync, event);
72265abebfaSPhilippe Houdoin		}
72325eb8cd7SIngo Weinhold	}
72425eb8cd7SIngo Weinhold
72525eb8cd7SIngo Weinhold	return B_OK;
72625eb8cd7SIngo Weinhold}
72725eb8cd7SIngo Weinhold
72825eb8cd7SIngo Weinhold
72925eb8cd7SIngo Weinholdstatus_t
7301ffa5029SAxel DörflerInode::Deselect(uint8 event, selectsync* sync, int openMode)
73125eb8cd7SIngo Weinhold{
73225eb8cd7SIngo Weinhold	select_sync_pool** pool;
73325eb8cd7SIngo Weinhold	if ((openMode & O_RWMASK) == O_RDONLY) {
73425eb8cd7SIngo Weinhold		pool = &fReadSelectSyncPool;
73525eb8cd7SIngo Weinhold	} else if ((openMode & O_RWMASK) == O_WRONLY) {
73625eb8cd7SIngo Weinhold		pool = &fWriteSelectSyncPool;
73725eb8cd7SIngo Weinhold	} else
73825eb8cd7SIngo Weinhold		return B_NOT_ALLOWED;
73925eb8cd7SIngo Weinhold
74025eb8cd7SIngo Weinhold	remove_select_sync_pool_entry(pool, sync, event);
74125eb8cd7SIngo Weinhold	return B_OK;
74225eb8cd7SIngo Weinhold}
74325eb8cd7SIngo Weinhold
74425eb8cd7SIngo Weinhold
74538b150a9SIngo Weinholdvoid
74638b150a9SIngo WeinholdInode::Dump(bool dumpData) const
74738b150a9SIngo Weinhold{
74838b150a9SIngo Weinhold	kprintf("FIFO %p\n", this);
74938b150a9SIngo Weinhold	kprintf("  active:        %s\n", fActive ? "true" : "false");
75038b150a9SIngo Weinhold	kprintf("  readers:       %" B_PRId32 "\n", fReaderCount);
75138b150a9SIngo Weinhold	kprintf("  writers:       %" B_PRId32 "\n", fWriterCount);
75238b150a9SIngo Weinhold
75338b150a9SIngo Weinhold	if (!fReadRequests.IsEmpty()) {
75438b150a9SIngo Weinhold		kprintf(" pending readers:\n");
75538b150a9SIngo Weinhold		for (ReadRequestList::ConstIterator it = fReadRequests.GetIterator();
75638b150a9SIngo Weinhold			ReadRequest* request = it.Next();) {
75738b150a9SIngo Weinhold			kprintf("    %p: thread %" B_PRId32 ", cookie: %p\n", request,
75838b150a9SIngo Weinhold				request->GetThread()->id, request->Cookie());
75938b150a9SIngo Weinhold		}
76038b150a9SIngo Weinhold	}
76138b150a9SIngo Weinhold
76238b150a9SIngo Weinhold	if (!fWriteRequests.IsEmpty()) {
76338b150a9SIngo Weinhold		kprintf(" pending writers:\n");
76438b150a9SIngo Weinhold		for (WriteRequestList::ConstIterator it = fWriteRequests.GetIterator();
76538b150a9SIngo Weinhold			WriteRequest* request = it.Next();) {
76638b150a9SIngo Weinhold			kprintf("    %p:  thread %" B_PRId32 ", min count: %zu\n", request,
76738b150a9SIngo Weinhold				request->GetThread()->id, request->MinimalWriteCount());
76838b150a9SIngo Weinhold		}
76938b150a9SIngo Weinhold	}
77038b150a9SIngo Weinhold
77138b150a9SIngo Weinhold	kprintf("  %zu bytes buffered\n", fBuffer.Readable());
77238b150a9SIngo Weinhold
77338b150a9SIngo Weinhold	if (dumpData && fBuffer.Readable() > 0) {
77438b150a9SIngo Weinhold		struct DataProvider : BKernel::HexDumpDataProvider {
77538b150a9SIngo Weinhold			DataProvider(const RingBuffer& buffer)
77638b150a9SIngo Weinhold				:
77738b150a9SIngo Weinhold				fBuffer(buffer),
77838b150a9SIngo Weinhold				fOffset(0)
77938b150a9SIngo Weinhold			{
78038b150a9SIngo Weinhold			}
78138b150a9SIngo Weinhold
78238b150a9SIngo Weinhold			virtual bool HasMoreData() const
78338b150a9SIngo Weinhold			{
78438b150a9SIngo Weinhold				return fOffset < fBuffer.Readable();
78538b150a9SIngo Weinhold			}
78638b150a9SIngo Weinhold
78738b150a9SIngo Weinhold			virtual uint8 NextByte()
78838b150a9SIngo Weinhold			{
78938b150a9SIngo Weinhold				uint8 byte = '\0';
79038b150a9SIngo Weinhold				if (fOffset < fBuffer.Readable()) {
79138b150a9SIngo Weinhold					fBuffer.Peek(fOffset, &byte, 1);
79238b150a9SIngo Weinhold					fOffset++;
79338b150a9SIngo Weinhold				}
79438b150a9SIngo Weinhold				return byte;
79538b150a9SIngo Weinhold			}
79638b150a9SIngo Weinhold
79738b150a9SIngo Weinhold			virtual bool GetAddressString(char* buffer, size_t bufferSize) const
79838b150a9SIngo Weinhold			{
79938b150a9SIngo Weinhold				snprintf(buffer, bufferSize, "    %4zx", fOffset);
80038b150a9SIngo Weinhold				return true;
80138b150a9SIngo Weinhold			}
80238b150a9SIngo Weinhold
80338b150a9SIngo Weinhold		private:
80438b150a9SIngo Weinhold			const RingBuffer&	fBuffer;
80538b150a9SIngo Weinhold			size_t				fOffset;
80638b150a9SIngo Weinhold		};
80738b150a9SIngo Weinhold
80838b150a9SIngo Weinhold		DataProvider dataProvider(fBuffer);
80938b150a9SIngo Weinhold		BKernel::print_hex_dump(dataProvider, fBuffer.Readable());
81038b150a9SIngo Weinhold	}
81138b150a9SIngo Weinhold}
81238b150a9SIngo Weinhold
81338b150a9SIngo Weinhold
81438b150a9SIngo Weinhold/*static*/ int
81538b150a9SIngo WeinholdInode::Dump(int argc, char** argv)
81638b150a9SIngo Weinhold{
81738b150a9SIngo Weinhold	bool dumpData = false;
81838b150a9SIngo Weinhold	int argi = 1;
81938b150a9SIngo Weinhold	if (argi < argc && strcmp(argv[argi], "-d") == 0) {
82038b150a9SIngo Weinhold		dumpData = true;
82138b150a9SIngo Weinhold		argi++;
82238b150a9SIngo Weinhold	}
82338b150a9SIngo Weinhold
82438b150a9SIngo Weinhold	if (argi >= argc || argi + 2 < argc) {
82538b150a9SIngo Weinhold		print_debugger_command_usage(argv[0]);
82638b150a9SIngo Weinhold		return 0;
82738b150a9SIngo Weinhold	}
82838b150a9SIngo Weinhold
82938b150a9SIngo Weinhold	Inode* node = (Inode*)parse_expression(argv[argi]);
83038b150a9SIngo Weinhold	if (IS_USER_ADDRESS(node)) {
83138b150a9SIngo Weinhold		kprintf("invalid FIFO address\n");
83238b150a9SIngo Weinhold		return 0;
83338b150a9SIngo Weinhold	}
83438b150a9SIngo Weinhold
83538b150a9SIngo Weinhold	node->Dump(dumpData);
83638b150a9SIngo Weinhold	return 0;
83738b150a9SIngo Weinhold}
83838b150a9SIngo Weinhold
83938b150a9SIngo Weinhold
8401ffa5029SAxel Dörfler//	#pragma mark - vnode API
84125eb8cd7SIngo Weinhold
84225eb8cd7SIngo Weinhold
84325eb8cd7SIngo Weinholdstatic status_t
8441ffa5029SAxel Dörflerfifo_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
84525eb8cd7SIngo Weinhold{
84625eb8cd7SIngo Weinhold	FIFOInode* fifo = (FIFOInode*)vnode->private_node;
84725eb8cd7SIngo Weinhold	fs_vnode* superVnode = fifo->SuperVnode();
84825eb8cd7SIngo Weinhold
84925eb8cd7SIngo Weinhold	status_t error = B_OK;
85025eb8cd7SIngo Weinhold	if (superVnode->ops->put_vnode != NULL)
85125eb8cd7SIngo Weinhold		error = superVnode->ops->put_vnode(volume, superVnode, reenter);
85225eb8cd7SIngo Weinhold
85325eb8cd7SIngo Weinhold	delete fifo;
85425eb8cd7SIngo Weinhold
85525eb8cd7SIngo Weinhold	return error;
85625eb8cd7SIngo Weinhold}
85725eb8cd7SIngo Weinhold
85825eb8cd7SIngo Weinhold
85925eb8cd7SIngo Weinholdstatic status_t
8601ffa5029SAxel Dörflerfifo_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
86125eb8cd7SIngo Weinhold{
86225eb8cd7SIngo Weinhold	FIFOInode* fifo = (FIFOInode*)vnode->private_node;
86325eb8cd7SIngo Weinhold	fs_vnode* superVnode = fifo->SuperVnode();
86425eb8cd7SIngo Weinhold
86525eb8cd7SIngo Weinhold	status_t error = B_OK;
86625eb8cd7SIngo Weinhold	if (superVnode->ops->remove_vnode != NULL)
86725eb8cd7SIngo Weinhold		error = superVnode->ops->remove_vnode(volume, superVnode, reenter);
86825eb8cd7SIngo Weinhold
86925eb8cd7SIngo Weinhold	delete fifo;
87025eb8cd7SIngo Weinhold
87125eb8cd7SIngo Weinhold	return error;
87225eb8cd7SIngo Weinhold}
87325eb8cd7SIngo Weinhold
87425eb8cd7SIngo Weinhold
87525eb8cd7SIngo Weinholdstatic status_t
8761ffa5029SAxel Dörflerfifo_open(fs_volume* _volume, fs_vnode* _node, int openMode,
8771ffa5029SAxel Dörfler	void** _cookie)
87825eb8cd7SIngo Weinhold{
8791ffa5029SAxel Dörfler	Inode* inode = (Inode*)_node->private_node;
88025eb8cd7SIngo Weinhold
8819061bf7eSAxel Dörfler	TRACE("fifo_open(): node = %p, openMode = %d\n", inode, openMode);
88225eb8cd7SIngo Weinhold
8831ffa5029SAxel Dörfler	file_cookie* cookie = (file_cookie*)malloc(sizeof(file_cookie));
88425eb8cd7SIngo Weinhold	if (cookie == NULL)
88525eb8cd7SIngo Weinhold		return B_NO_MEMORY;
88625eb8cd7SIngo Weinhold
8879061bf7eSAxel Dörfler	TRACE("  open cookie = %p\n", cookie);
88825eb8cd7SIngo Weinhold	cookie->open_mode = openMode;
88925eb8cd7SIngo Weinhold	inode->Open(openMode);
89025eb8cd7SIngo Weinhold
8911ffa5029SAxel Dörfler	*_cookie = (void*)cookie;
89225eb8cd7SIngo Weinhold
89325eb8cd7SIngo Weinhold	return B_OK;
89425eb8cd7SIngo Weinhold}
89525eb8cd7SIngo Weinhold
89625eb8cd7SIngo Weinhold
89725eb8cd7SIngo Weinholdstatic status_t
8981ffa5029SAxel Dörflerfifo_close(fs_volume* volume, fs_vnode* vnode, void* _cookie)
89925eb8cd7SIngo Weinhold{
9001ffa5029SAxel Dörfler	file_cookie* cookie = (file_cookie*)_cookie;
90125eb8cd7