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