Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/winpr/libwinpr/utils/collections/PubSub.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Publisher/Subscriber Pattern
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include <winpr/crt.h>
23
24
#include <winpr/collections.h>
25
26
/**
27
 * Events (C# Programming Guide)
28
 * http://msdn.microsoft.com/en-us/library/awbftdfh.aspx
29
 */
30
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
41
/**
42
 * Properties
43
 */
44
45
wEventType* PubSub_GetEventTypes(wPubSub* pubSub, size_t* count)
46
0
{
47
0
  WINPR_ASSERT(pubSub);
48
0
  if (count)
49
0
    *count = pubSub->count;
50
51
0
  return pubSub->events;
52
0
}
53
54
/**
55
 * Methods
56
 */
57
58
void PubSub_Lock(wPubSub* pubSub)
59
23.8k
{
60
23.8k
  WINPR_ASSERT(pubSub);
61
23.8k
  if (pubSub->synchronized)
62
23.8k
    EnterCriticalSection(&pubSub->lock);
63
23.8k
}
64
65
void PubSub_Unlock(wPubSub* pubSub)
66
23.8k
{
67
23.8k
  WINPR_ASSERT(pubSub);
68
23.8k
  if (pubSub->synchronized)
69
23.8k
    LeaveCriticalSection(&pubSub->lock);
70
23.8k
}
71
72
wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName)
73
15.8k
{
74
15.8k
  wEventType* event = NULL;
75
76
15.8k
  WINPR_ASSERT(pubSub);
77
15.8k
  WINPR_ASSERT(EventName);
78
138k
  for (size_t index = 0; index < pubSub->count; index++)
79
122k
  {
80
122k
    if (strcmp(pubSub->events[index].EventName, EventName) == 0)
81
374
    {
82
374
      event = &(pubSub->events[index]);
83
374
      break;
84
374
    }
85
122k
  }
86
87
15.8k
  return event;
88
15.8k
}
89
90
void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, size_t count)
91
7.99k
{
92
7.99k
  WINPR_ASSERT(pubSub);
93
7.99k
  WINPR_ASSERT(events || (count == 0));
94
7.99k
  if (pubSub->synchronized)
95
7.99k
    PubSub_Lock(pubSub);
96
97
7.99k
  while (pubSub->count + count >= pubSub->size)
98
0
  {
99
0
    size_t new_size = 0;
100
0
    wEventType* new_event = NULL;
101
102
0
    new_size = pubSub->size * 2;
103
0
    new_event = (wEventType*)realloc(pubSub->events, new_size * sizeof(wEventType));
104
0
    if (!new_event)
105
0
      goto fail;
106
0
    pubSub->size = new_size;
107
0
    pubSub->events = new_event;
108
0
  }
109
110
7.99k
  CopyMemory(&pubSub->events[pubSub->count], events, count * sizeof(wEventType));
111
7.99k
  pubSub->count += count;
112
113
7.99k
fail:
114
7.99k
  if (pubSub->synchronized)
115
7.99k
    PubSub_Unlock(pubSub);
116
7.99k
}
117
118
int PubSub_Subscribe(wPubSub* pubSub, const char* EventName, ...)
119
0
{
120
0
  wEventType* event = NULL;
121
0
  int status = -1;
122
0
  WINPR_ASSERT(pubSub);
123
124
0
  va_list ap;
125
0
  va_start(ap, EventName);
126
0
  pEventHandler EventHandler = va_arg(ap, pEventHandler);
127
128
0
  if (pubSub->synchronized)
129
0
    PubSub_Lock(pubSub);
130
131
0
  event = PubSub_FindEventType(pubSub, EventName);
132
133
0
  if (event)
134
0
  {
135
0
    status = 0;
136
137
0
    if (event->EventHandlerCount < MAX_EVENT_HANDLERS)
138
0
      event->EventHandlers[event->EventHandlerCount++] = EventHandler;
139
0
    else
140
0
      status = -1;
141
0
  }
142
143
0
  if (pubSub->synchronized)
144
0
    PubSub_Unlock(pubSub);
145
146
0
  va_end(ap);
147
0
  return status;
148
0
}
149
150
int PubSub_Unsubscribe(wPubSub* pubSub, const char* EventName, ...)
151
0
{
152
0
  wEventType* event = NULL;
153
0
  int status = -1;
154
0
  WINPR_ASSERT(pubSub);
155
0
  WINPR_ASSERT(EventName);
156
157
0
  va_list ap;
158
0
  va_start(ap, EventName);
159
0
  pEventHandler EventHandler = va_arg(ap, pEventHandler);
160
161
0
  if (pubSub->synchronized)
162
0
    PubSub_Lock(pubSub);
163
164
0
  event = PubSub_FindEventType(pubSub, EventName);
165
166
0
  if (event)
167
0
  {
168
0
    status = 0;
169
170
0
    for (size_t index = 0; index < event->EventHandlerCount; index++)
171
0
    {
172
0
      if (event->EventHandlers[index] == EventHandler)
173
0
      {
174
0
        event->EventHandlers[index] = NULL;
175
0
        event->EventHandlerCount--;
176
0
        MoveMemory(&event->EventHandlers[index], &event->EventHandlers[index + 1],
177
0
                   (MAX_EVENT_HANDLERS - index - 1) * sizeof(pEventHandler));
178
0
        status = 1;
179
0
      }
180
0
    }
181
0
  }
182
183
0
  if (pubSub->synchronized)
184
0
    PubSub_Unlock(pubSub);
185
186
0
  va_end(ap);
187
0
  return status;
188
0
}
189
190
int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, const wEventArgs* e)
191
15.8k
{
192
15.8k
  wEventType* event = NULL;
193
15.8k
  int status = -1;
194
195
15.8k
  if (!pubSub)
196
0
    return -1;
197
15.8k
  WINPR_ASSERT(e);
198
199
15.8k
  if (pubSub->synchronized)
200
15.8k
    PubSub_Lock(pubSub);
201
202
15.8k
  event = PubSub_FindEventType(pubSub, EventName);
203
204
15.8k
  if (pubSub->synchronized)
205
15.8k
    PubSub_Unlock(pubSub);
206
207
15.8k
  if (event)
208
374
  {
209
374
    status = 0;
210
211
374
    for (size_t index = 0; index < event->EventHandlerCount; index++)
212
0
    {
213
0
      if (event->EventHandlers[index])
214
0
      {
215
0
        event->EventHandlers[index](context, e);
216
0
        status++;
217
0
      }
218
0
    }
219
374
  }
220
221
15.8k
  return status;
222
15.8k
}
223
224
/**
225
 * Construction, Destruction
226
 */
227
228
wPubSub* PubSub_New(BOOL synchronized)
229
14.9k
{
230
14.9k
  wPubSub* pubSub = (wPubSub*)calloc(1, sizeof(wPubSub));
231
232
14.9k
  if (!pubSub)
233
0
    return NULL;
234
235
14.9k
  pubSub->synchronized = synchronized;
236
237
14.9k
  if (pubSub->synchronized && !InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000))
238
0
    goto fail;
239
240
14.9k
  pubSub->count = 0;
241
14.9k
  pubSub->size = 64;
242
243
14.9k
  pubSub->events = (wEventType*)calloc(pubSub->size, sizeof(wEventType));
244
14.9k
  if (!pubSub->events)
245
0
    goto fail;
246
247
14.9k
  return pubSub;
248
0
fail:
249
0
  WINPR_PRAGMA_DIAG_PUSH
250
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
251
0
  PubSub_Free(pubSub);
252
0
  WINPR_PRAGMA_DIAG_POP
253
0
  return NULL;
254
14.9k
}
255
256
void PubSub_Free(wPubSub* pubSub)
257
14.9k
{
258
14.9k
  if (pubSub)
259
14.9k
  {
260
14.9k
    if (pubSub->synchronized)
261
14.9k
      DeleteCriticalSection(&pubSub->lock);
262
263
14.9k
    free(pubSub->events);
264
14.9k
    free(pubSub);
265
14.9k
  }
266
14.9k
}