1/*
2 * Copyright 2007-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2019, Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6#ifndef _KERNEL_CONDITION_VARIABLE_H
7#define _KERNEL_CONDITION_VARIABLE_H
8
9
10#include <OS.h>
11
12#include <debug.h>
13
14#ifdef __cplusplus
15
16#include <util/DoublyLinkedList.h>
17#include <util/OpenHashTable.h>
18
19
20struct ConditionVariable;
21
22
23struct ConditionVariableEntry
24	: DoublyLinkedListLinkImpl<ConditionVariableEntry> {
25public:
26#if KDEBUG
27	inline						ConditionVariableEntry();
28	inline						~ConditionVariableEntry();
29#endif
30
31			bool				Add(const void* object);
32			status_t			Wait(uint32 flags = 0, bigtime_t timeout = 0);
33			status_t			Wait(const void* object, uint32 flags = 0,
34									bigtime_t timeout = 0);
35
36	inline	status_t			WaitStatus() const { return fWaitStatus; }
37
38	inline	ConditionVariable*	Variable() const { return fVariable; }
39
40private:
41	inline	void				AddToLockedVariable(ConditionVariable* variable);
42
43private:
44			spinlock			fLock;
45			ConditionVariable*	fVariable;
46			Thread*				fThread;
47			status_t			fWaitStatus;
48
49			friend struct ConditionVariable;
50};
51
52
53struct ConditionVariable {
54public:
55			void				Init(const void* object,
56									const char* objectType);
57									// for anonymous (unpublished) cvars
58
59			void				Publish(const void* object,
60									const char* objectType);
61			void				Unpublish();
62
63	inline	void				NotifyOne(status_t result = B_OK);
64	inline	void				NotifyAll(status_t result = B_OK);
65
66	static	void				NotifyOne(const void* object, status_t result);
67	static	void				NotifyAll(const void* object, status_t result);
68									// (both methods) caller must ensure that
69									// the variable is not unpublished
70									// concurrently
71
72			void				Add(ConditionVariableEntry* entry);
73
74			status_t			Wait(uint32 flags = 0, bigtime_t timeout = 0);
75									// all-in one, i.e. doesn't need a
76									// ConditionVariableEntry
77
78			const void*			Object() const		{ return fObject; }
79			const char*			ObjectType() const	{ return fObjectType; }
80
81	static	void				ListAll();
82			void				Dump() const;
83
84private:
85			void				_Notify(bool all, status_t result);
86			void				_NotifyLocked(bool all, status_t result);
87
88protected:
89			typedef DoublyLinkedList<ConditionVariableEntry> EntryList;
90
91			const void*			fObject;
92			const char*			fObjectType;
93
94			spinlock			fLock;
95			EntryList			fEntries;
96			ConditionVariable*	fNext;
97
98			friend struct ConditionVariableEntry;
99			friend struct ConditionVariableHashDefinition;
100};
101
102
103#if KDEBUG
104
105inline
106ConditionVariableEntry::ConditionVariableEntry()
107	: fVariable(NULL)
108{
109}
110
111inline
112ConditionVariableEntry::~ConditionVariableEntry()
113{
114	if (fVariable != NULL) {
115		panic("Destroying condition variable entry %p, but it's still "
116			"attached to variable %p\n", this, fVariable);
117	}
118}
119
120#endif
121
122
123inline void
124ConditionVariable::NotifyOne(status_t result)
125{
126	_Notify(false, result);
127}
128
129
130inline void
131ConditionVariable::NotifyAll(status_t result)
132{
133	_Notify(true, result);
134}
135
136
137extern "C" {
138#endif	// __cplusplus
139
140extern void condition_variable_init();
141
142#ifdef __cplusplus
143}	// extern "C"
144#endif
145
146#endif	/* _KERNEL_CONDITION_VARIABLE_H */
147