FreeRDP
Loading...
Searching...
No Matches
PubSub.c
1
20#include <winpr/config.h>
21
22#include <winpr/crt.h>
23
24#include <winpr/collections.h>
25
31struct s_wPubSub
32{
34 BOOL synchronized;
35
36 size_t size;
37 size_t count;
38 wEventType* events;
39};
40
45wEventType* PubSub_GetEventTypes(wPubSub* pubSub, size_t* count)
46{
47 WINPR_ASSERT(pubSub);
48 if (count)
49 *count = pubSub->count;
50
51 return pubSub->events;
52}
53
58void PubSub_Lock(wPubSub* pubSub)
59{
60 WINPR_ASSERT(pubSub);
61 if (pubSub->synchronized)
62 EnterCriticalSection(&pubSub->lock);
63}
64
65void PubSub_Unlock(wPubSub* pubSub)
66{
67 WINPR_ASSERT(pubSub);
68 if (pubSub->synchronized)
69 LeaveCriticalSection(&pubSub->lock);
70}
71
72wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName)
73{
74 wEventType* event = NULL;
75
76 WINPR_ASSERT(pubSub);
77 WINPR_ASSERT(EventName);
78 for (size_t index = 0; index < pubSub->count; index++)
79 {
80 if (strcmp(pubSub->events[index].EventName, EventName) == 0)
81 {
82 event = &(pubSub->events[index]);
83 break;
84 }
85 }
86
87 return event;
88}
89
90void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, size_t count)
91{
92 WINPR_ASSERT(pubSub);
93 WINPR_ASSERT(events || (count == 0));
94 if (pubSub->synchronized)
95 PubSub_Lock(pubSub);
96
97 const size_t required = pubSub->count + count;
98 WINPR_ASSERT((required >= pubSub->count) && (required >= count));
99
100 if (required >= pubSub->size)
101 {
102 size_t new_size = pubSub->size;
103 do
104 {
105 WINPR_ASSERT(new_size <= SIZE_MAX - 128ull);
106 new_size += 128ull;
107 } while (new_size <= required);
108
109 wEventType* new_event = (wEventType*)realloc(pubSub->events, new_size * sizeof(wEventType));
110 if (!new_event)
111 goto fail;
112 pubSub->size = new_size;
113 pubSub->events = new_event;
114 }
115
116 CopyMemory(&pubSub->events[pubSub->count], events, count * sizeof(wEventType));
117 pubSub->count += count;
118
119fail:
120 if (pubSub->synchronized)
121 PubSub_Unlock(pubSub);
122}
123
124int PubSub_Subscribe(wPubSub* pubSub, const char* EventName, ...)
125{
126 wEventType* event = NULL;
127 int status = -1;
128 WINPR_ASSERT(pubSub);
129
130 va_list ap = { 0 };
131 va_start(ap, EventName);
132 pEventHandler EventHandler = va_arg(ap, pEventHandler);
133
134 if (pubSub->synchronized)
135 PubSub_Lock(pubSub);
136
137 event = PubSub_FindEventType(pubSub, EventName);
138
139 if (event)
140 {
141 status = 0;
142
143 if (event->EventHandlerCount < MAX_EVENT_HANDLERS)
144 event->EventHandlers[event->EventHandlerCount++] = EventHandler;
145 else
146 status = -1;
147 }
148
149 if (pubSub->synchronized)
150 PubSub_Unlock(pubSub);
151
152 va_end(ap);
153 return status;
154}
155
156int PubSub_Unsubscribe(wPubSub* pubSub, const char* EventName, ...)
157{
158 wEventType* event = NULL;
159 int status = -1;
160 WINPR_ASSERT(pubSub);
161 WINPR_ASSERT(EventName);
162
163 va_list ap = { 0 };
164 va_start(ap, EventName);
165 pEventHandler EventHandler = va_arg(ap, pEventHandler);
166
167 if (pubSub->synchronized)
168 PubSub_Lock(pubSub);
169
170 event = PubSub_FindEventType(pubSub, EventName);
171
172 if (event)
173 {
174 status = 0;
175
176 for (size_t index = 0; index < event->EventHandlerCount; index++)
177 {
178 if (event->EventHandlers[index] == EventHandler)
179 {
180 event->EventHandlers[index] = NULL;
181 event->EventHandlerCount--;
182 MoveMemory((void*)&event->EventHandlers[index],
183 (void*)&event->EventHandlers[index + 1],
184 (MAX_EVENT_HANDLERS - index - 1) * sizeof(pEventHandler));
185 status = 1;
186 }
187 }
188 }
189
190 if (pubSub->synchronized)
191 PubSub_Unlock(pubSub);
192
193 va_end(ap);
194 return status;
195}
196
197int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, const wEventArgs* e)
198{
199 wEventType* event = NULL;
200 int status = -1;
201
202 if (!pubSub)
203 return -1;
204 WINPR_ASSERT(e);
205
206 if (pubSub->synchronized)
207 PubSub_Lock(pubSub);
208
209 event = PubSub_FindEventType(pubSub, EventName);
210
211 if (pubSub->synchronized)
212 PubSub_Unlock(pubSub);
213
214 if (event)
215 {
216 status = 0;
217
218 for (size_t index = 0; index < event->EventHandlerCount; index++)
219 {
220 if (event->EventHandlers[index])
221 {
222 event->EventHandlers[index](context, e);
223 status++;
224 }
225 }
226 }
227
228 return status;
229}
230
235wPubSub* PubSub_New(BOOL synchronized)
236{
237 wPubSub* pubSub = (wPubSub*)calloc(1, sizeof(wPubSub));
238
239 if (!pubSub)
240 return NULL;
241
242 pubSub->synchronized = synchronized;
243
244 if (pubSub->synchronized && !InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000))
245 goto fail;
246
247 pubSub->count = 0;
248 pubSub->size = 64;
249
250 pubSub->events = (wEventType*)calloc(pubSub->size, sizeof(wEventType));
251 if (!pubSub->events)
252 goto fail;
253
254 return pubSub;
255fail:
256 WINPR_PRAGMA_DIAG_PUSH
257 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
258 PubSub_Free(pubSub);
259 WINPR_PRAGMA_DIAG_POP
260 return NULL;
261}
262
263void PubSub_Free(wPubSub* pubSub)
264{
265 if (pubSub)
266 {
267 if (pubSub->synchronized)
268 DeleteCriticalSection(&pubSub->lock);
269
270 free(pubSub->events);
271 free(pubSub);
272 }
273}