1/*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef UNIX_FIFO_H
6#define UNIX_FIFO_H
7
8#include <Referenceable.h>
9
10#include <condition_variable.h>
11#include <lock.h>
12#include <util/AutoLock.h>
13#include <util/DoublyLinkedList.h>
14
15#include <net_buffer.h>
16
17
18#define UNIX_FIFO_SHUTDOWN_READ		1
19#define UNIX_FIFO_SHUTDOWN_WRITE	2
20
21#define UNIX_FIFO_SHUTDOWN			(B_ERRORS_END + 1)
22	// error code returned by Read()/Write()
23
24#define UNIX_FIFO_MINIMAL_CAPACITY	1024
25#define UNIX_FIFO_MAXIMAL_CAPACITY	(128 * 1024)
26
27
28struct ring_buffer;
29
30class UnixRequest : public DoublyLinkedListLinkImpl<UnixRequest> {
31public:
32	UnixRequest(const iovec* vecs, size_t count,
33			ancillary_data_container* ancillaryData);
34
35	off_t TotalSize() const			{ return fTotalSize; }
36	off_t BytesTransferred() const	{ return fBytesTransferred; }
37	off_t BytesRemaining() const	{ return fTotalSize - fBytesTransferred; }
38
39	void AddBytesTransferred(size_t size);
40	bool GetCurrentChunk(void*& data, size_t& size);
41
42	ancillary_data_container* AncillaryData() const	 { return fAncillaryData; }
43	void SetAncillaryData(ancillary_data_container* data);
44	void AddAncillaryData(ancillary_data_container* data);
45
46private:
47	const iovec*				fVecs;
48	size_t						fVecCount;
49	ancillary_data_container*	fAncillaryData;
50	off_t						fTotalSize;
51	off_t						fBytesTransferred;
52	size_t						fVecIndex;
53	size_t						fVecOffset;
54};
55
56
57class UnixBufferQueue {
58public:
59	UnixBufferQueue(size_t capacity);
60	~UnixBufferQueue();
61
62	status_t Init();
63
64	size_t	Readable() const;
65	size_t	Writable() const;
66
67	status_t Read(UnixRequest& request);
68	status_t Write(UnixRequest& request);
69
70	size_t Capacity() const				{ return fCapacity; }
71	status_t SetCapacity(size_t capacity);
72
73private:
74	struct AncillaryDataEntry : DoublyLinkedListLinkImpl<AncillaryDataEntry> {
75		ancillary_data_container*	data;
76		size_t						offset;
77	};
78
79	typedef DoublyLinkedList<AncillaryDataEntry> AncillaryDataList;
80
81	ring_buffer*		fBuffer;
82	size_t				fCapacity;
83	AncillaryDataList	fAncillaryData;
84};
85
86
87class UnixFifo : public BReferenceable {
88public:
89	UnixFifo(size_t capacity);
90	~UnixFifo();
91
92	status_t Init();
93
94	bool Lock()
95	{
96		return mutex_lock(&fLock) == B_OK;
97	}
98
99	void Unlock()
100	{
101		mutex_unlock(&fLock);
102	}
103
104	void Shutdown(uint32 shutdown);
105
106	bool IsReadShutdown() const
107	{
108		return (fShutdown & UNIX_FIFO_SHUTDOWN_READ);
109	}
110
111	bool IsWriteShutdown() const
112	{
113		return (fShutdown & UNIX_FIFO_SHUTDOWN_WRITE);
114	}
115
116	ssize_t Read(const iovec* vecs, size_t vecCount,
117		ancillary_data_container** _ancillaryData, bigtime_t timeout);
118	ssize_t Write(const iovec* vecs, size_t vecCount,
119		ancillary_data_container* ancillaryData, bigtime_t timeout);
120
121	size_t Readable() const;
122	size_t Writable() const;
123
124	status_t SetBufferCapacity(size_t capacity);
125
126private:
127	typedef DoublyLinkedList<UnixRequest> RequestList;
128
129private:
130	status_t _Read(UnixRequest& request, bigtime_t timeout);
131	status_t _Write(UnixRequest& request, bigtime_t timeout);
132	status_t _WriteNonBlocking(UnixRequest& request);
133
134private:
135	mutex				fLock;
136	UnixBufferQueue		fBuffer;
137	RequestList			fReaders;
138	RequestList			fWriters;
139	off_t				fReadRequested;
140	off_t				fWriteRequested;
141	ConditionVariable	fReadCondition;
142	ConditionVariable	fWriteCondition;
143	uint32				fShutdown;
144};
145
146
147typedef AutoLocker<UnixFifo> UnixFifoLocker;
148
149
150#endif	// UNIX_FIFO_H
151