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(&event->EventHandlers[index], &event->EventHandlers[index + 1],
177  (MAX_EVENT_HANDLERS - index - 1) * sizeof(pEventHandler));
178  status = 1;
179  }
180  }
181  }
182 
183  if (pubSub->synchronized)
184  PubSub_Unlock(pubSub);
185 
186  va_end(ap);
187  return status;
188 }
189 
190 int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, const wEventArgs* e)
191 {
192  wEventType* event = NULL;
193  int status = -1;
194 
195  if (!pubSub)
196  return -1;
197  WINPR_ASSERT(e);
198 
199  if (pubSub->synchronized)
200  PubSub_Lock(pubSub);
201 
202  event = PubSub_FindEventType(pubSub, EventName);
203 
204  if (pubSub->synchronized)
205  PubSub_Unlock(pubSub);
206 
207  if (event)
208  {
209  status = 0;
210 
211  for (size_t index = 0; index < event->EventHandlerCount; index++)
212  {
213  if (event->EventHandlers[index])
214  {
215  event->EventHandlers[index](context, e);
216  status++;
217  }
218  }
219  }
220 
221  return status;
222 }
223 
228 wPubSub* PubSub_New(BOOL synchronized)
229 {
230  wPubSub* pubSub = (wPubSub*)calloc(1, sizeof(wPubSub));
231 
232  if (!pubSub)
233  return NULL;
234 
235  pubSub->synchronized = synchronized;
236 
237  if (pubSub->synchronized && !InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000))
238  goto fail;
239 
240  pubSub->count = 0;
241  pubSub->size = 64;
242 
243  pubSub->events = (wEventType*)calloc(pubSub->size, sizeof(wEventType));
244  if (!pubSub->events)
245  goto fail;
246 
247  return pubSub;
248 fail:
249  WINPR_PRAGMA_DIAG_PUSH
250  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
251  PubSub_Free(pubSub);
252  WINPR_PRAGMA_DIAG_POP
253  return NULL;
254 }
255 
256 void PubSub_Free(wPubSub* pubSub)
257 {
258  if (pubSub)
259  {
260  if (pubSub->synchronized)
261  DeleteCriticalSection(&pubSub->lock);
262 
263  free(pubSub->events);
264  free(pubSub);
265  }
266 }