24 #include "../synch/pollset.h"
25 #include <winpr/assert.h>
27 #define TAG WINPR_TAG("apc")
31 pthread_mutexattr_t attr;
36 pthread_mutexattr_init(&attr);
37 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
39 WLog_ERR(TAG,
"failed to initialize mutex attributes to recursive");
43 memset(apc, 0,
sizeof(*apc));
45 if (pthread_mutex_init(&apc->mutex, &attr) != 0)
47 WLog_ERR(TAG,
"failed to initialize main thread APC mutex");
53 pthread_mutexattr_destroy(&attr);
60 return pthread_mutex_destroy(&apc->mutex) == 0;
63 void apc_register(WINPR_THREAD* thread, WINPR_APC_ITEM* addItem)
65 WINPR_APC_ITEM** nextp = NULL;
69 WINPR_ASSERT(addItem);
74 pthread_mutex_lock(&apc->mutex);
77 nextp = &apc->tail->next;
78 addItem->last = apc->tail;
89 addItem->markedForRemove = FALSE;
90 addItem->boundThread = GetCurrentThreadId();
91 addItem->linked = TRUE;
92 pthread_mutex_unlock(&apc->mutex);
95 static INLINE
void apc_item_remove(
APC_QUEUE* apc, WINPR_APC_ITEM* item)
101 apc->head = item->next;
103 item->last->next = item->next;
106 apc->tail = item->last;
108 item->next->last = item->last;
113 APC_REMOVE_RESULT apc_remove(WINPR_APC_ITEM* item)
115 WINPR_THREAD* thread = winpr_GetCurrentThread();
117 APC_REMOVE_RESULT ret = APC_REMOVE_OK;
122 return APC_REMOVE_OK;
124 if (item->boundThread != GetCurrentThreadId())
126 WLog_ERR(TAG,
"removing an APC entry should be done in the creating thread");
127 return APC_REMOVE_ERROR;
132 WLog_ERR(TAG,
"unable to retrieve current thread");
133 return APC_REMOVE_ERROR;
139 pthread_mutex_lock(&apc->mutex);
140 if (apc->treatingCompletions)
142 item->markedForRemove = TRUE;
143 ret = APC_REMOVE_DELAY_FREE;
147 apc_item_remove(apc, item);
150 pthread_mutex_unlock(&apc->mutex);
151 item->boundThread = 0xFFFFFFFF;
152 item->linked = FALSE;
156 BOOL apc_collectFds(WINPR_THREAD* thread, WINPR_POLL_SET* set, BOOL* haveAutoSignaled)
158 WINPR_APC_ITEM* item = NULL;
162 WINPR_ASSERT(thread);
163 WINPR_ASSERT(haveAutoSignaled);
168 *haveAutoSignaled = FALSE;
169 pthread_mutex_lock(&apc->mutex);
171 for (; item; item = item->next)
173 if (item->alwaysSignaled)
175 *haveAutoSignaled = TRUE;
177 else if (!pollset_add(set, item->pollFd, item->pollMode))
183 pthread_mutex_unlock(&apc->mutex);
187 int apc_executeCompletions(WINPR_THREAD* thread, WINPR_POLL_SET* set,
size_t startIndex)
190 WINPR_APC_ITEM* nextItem = NULL;
191 size_t idx = startIndex;
194 WINPR_ASSERT(thread);
199 pthread_mutex_lock(&apc->mutex);
200 apc->treatingCompletions = TRUE;
203 for (WINPR_APC_ITEM* item = apc->head; item; item = item->next)
205 item->isSignaled = item->alwaysSignaled || pollset_isSignaled(set, idx);
206 if (!item->alwaysSignaled)
211 for (WINPR_APC_ITEM* item = apc->head; item; item = nextItem)
213 if (item->isSignaled)
215 if (item->completion && !item->markedForRemove)
216 item->completion(item->completionArgs);
220 nextItem = item->next;
224 for (WINPR_APC_ITEM* item = apc->head; item; item = nextItem)
226 nextItem = item->next;
228 if (item->markedForRemove)
230 apc_item_remove(apc, item);
231 if (item->markedForFree)
236 apc->treatingCompletions = FALSE;
237 pthread_mutex_unlock(&apc->mutex);
242 void apc_cleanupThread(WINPR_THREAD* thread)
244 WINPR_APC_ITEM* item = NULL;
245 WINPR_APC_ITEM* nextItem = NULL;
248 WINPR_ASSERT(thread);
253 pthread_mutex_lock(&apc->mutex);
255 for (; item; item = nextItem)
257 nextItem = item->next;
259 if (item->type == APC_TYPE_HANDLE_FREE)
260 item->completion(item->completionArgs);
262 item->last = item->next = NULL;
263 item->linked = FALSE;
264 if (item->markedForFree)
268 apc->head = apc->tail = NULL;
269 pthread_mutex_unlock(&apc->mutex);