Coverage Report

Created: 2026-03-04 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/utils/collections/ObjectPool.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Object Pool
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
#include <winpr/assert.h>
24
25
#include <winpr/collections.h>
26
27
struct s_wObjectPool
28
{
29
  size_t size;
30
  size_t capacity;
31
  void** array;
32
  CRITICAL_SECTION lock;
33
  wObject object;
34
  BOOL synchronized;
35
};
36
37
/**
38
 * C Object Pool similar to C# BufferManager Class:
39
 * http://msdn.microsoft.com/en-us/library/ms405814.aspx
40
 */
41
42
/**
43
 * Methods
44
 */
45
46
static void ObjectPool_Lock(wObjectPool* pool)
47
11.3k
{
48
11.3k
  WINPR_ASSERT(pool);
49
11.3k
  if (pool->synchronized)
50
11.3k
    EnterCriticalSection(&pool->lock);
51
11.3k
}
52
53
static void ObjectPool_Unlock(wObjectPool* pool)
54
11.3k
{
55
11.3k
  WINPR_ASSERT(pool);
56
11.3k
  if (pool->synchronized)
57
11.3k
    LeaveCriticalSection(&pool->lock);
58
11.3k
}
59
60
/**
61
 * Gets an object from the pool.
62
 */
63
64
void* ObjectPool_Take(wObjectPool* pool)
65
0
{
66
0
  void* obj = nullptr;
67
68
0
  ObjectPool_Lock(pool);
69
70
0
  if (pool->size > 0)
71
0
    obj = pool->array[--(pool->size)];
72
73
0
  if (!obj)
74
0
  {
75
0
    if (pool->object.fnObjectNew)
76
0
      obj = pool->object.fnObjectNew(nullptr);
77
0
  }
78
79
0
  if (pool->object.fnObjectInit)
80
0
    pool->object.fnObjectInit(obj);
81
82
0
  ObjectPool_Unlock(pool);
83
84
0
  return obj;
85
0
}
86
87
static BOOL ObjectPool_EnsureCapacity(wObjectPool* pool, size_t add)
88
11.3k
{
89
11.3k
  WINPR_ASSERT(pool->size < SIZE_MAX - add);
90
91
11.3k
  const size_t blocksize = 128ull;
92
11.3k
  const size_t required = pool->size + add;
93
11.3k
  if (required >= pool->capacity)
94
11.3k
  {
95
11.3k
    const size_t new_cap = required + blocksize - required % blocksize;
96
97
11.3k
    void** new_arr = (void**)realloc((void*)pool->array, sizeof(void*) * new_cap);
98
11.3k
    if (!new_arr)
99
0
      return FALSE;
100
101
11.3k
    pool->array = new_arr;
102
11.3k
    pool->capacity = new_cap;
103
11.3k
  }
104
11.3k
  return TRUE;
105
11.3k
}
106
107
/**
108
 * Returns an object to the pool.
109
 */
110
111
void ObjectPool_Return(wObjectPool* pool, void* obj)
112
0
{
113
0
  ObjectPool_Lock(pool);
114
115
0
  if (!ObjectPool_EnsureCapacity(pool, 1))
116
0
    goto out;
117
118
0
  pool->array[(pool->size)++] = obj;
119
120
0
  if (pool->object.fnObjectUninit)
121
0
    pool->object.fnObjectUninit(obj);
122
123
0
out:
124
0
  ObjectPool_Unlock(pool);
125
0
}
126
127
wObject* ObjectPool_Object(wObjectPool* pool)
128
11.3k
{
129
11.3k
  WINPR_ASSERT(pool);
130
11.3k
  return &pool->object;
131
11.3k
}
132
133
/**
134
 * Releases the buffers currently cached in the pool.
135
 */
136
137
void ObjectPool_Clear(wObjectPool* pool)
138
11.3k
{
139
11.3k
  ObjectPool_Lock(pool);
140
141
11.3k
  while (pool->size > 0)
142
0
  {
143
0
    (pool->size)--;
144
145
0
    if (pool->object.fnObjectFree)
146
0
      pool->object.fnObjectFree(pool->array[pool->size]);
147
0
  }
148
149
11.3k
  ObjectPool_Unlock(pool);
150
11.3k
}
151
152
/**
153
 * Construction, Destruction
154
 */
155
156
wObjectPool* ObjectPool_New(BOOL synchronized)
157
11.3k
{
158
11.3k
  wObjectPool* pool = (wObjectPool*)calloc(1, sizeof(wObjectPool));
159
160
11.3k
  if (!pool)
161
0
    goto fail;
162
163
11.3k
  pool->synchronized = synchronized;
164
165
11.3k
  if (pool->synchronized)
166
11.3k
  {
167
11.3k
    if (!InitializeCriticalSectionAndSpinCount(&pool->lock, 4000))
168
0
      goto fail;
169
11.3k
  }
170
171
11.3k
  if (!ObjectPool_EnsureCapacity(pool, 32))
172
0
    goto fail;
173
174
11.3k
  return pool;
175
176
0
fail:
177
0
  ObjectPool_Free(pool);
178
0
  return nullptr;
179
11.3k
}
180
181
void ObjectPool_Free(wObjectPool* pool)
182
11.3k
{
183
11.3k
  if (!pool)
184
0
    return;
185
186
11.3k
  ObjectPool_Clear(pool);
187
188
11.3k
  if (pool->synchronized)
189
11.3k
    DeleteCriticalSection(&pool->lock);
190
191
11.3k
  free((void*)pool->array);
192
193
11.3k
  free(pool);
194
11.3k
}