/* Copyright (C) 2006-2009 Ricardo Pescuma Domenecci This is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this file; see the file license.txt. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ContactAsyncQueue.h" #include // Itens with higher time at end static int QueueSortItems(const QueueItem *oldItem, const QueueItem *newItem) { if (oldItem->check_time == newItem->check_time) return -1; return oldItem->check_time - newItem->check_time; } // Itens with higher time at end static void ContactAsyncQueueThread(void *obj) { ((ContactAsyncQueue *)obj)->Thread(); } ContactAsyncQueue::ContactAsyncQueue(pfContactAsyncQueueCallback fContactAsyncQueueCallback, int initialSize) : queue(30, QueueSortItems) { hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); finished = 0; callback = fContactAsyncQueueCallback; InitializeCriticalSection(&cs); _beginthread(ContactAsyncQueueThread, 0, this); //mir_forkthread(ContactAsyncQueueThread, this); } ContactAsyncQueue::~ContactAsyncQueue() { Finish(); int count = 0; while(finished != 2 && ++count < 50) Sleep(30); for (int i = 0; i < queue.getCount(); i++) if (queue[i] != NULL) mir_free(queue[i]); DeleteCriticalSection(&cs); } void ContactAsyncQueue::Finish() { if (finished == 0) finished = 1; SetEvent(hEvent); } void ContactAsyncQueue::Lock() { EnterCriticalSection(&cs); } void ContactAsyncQueue::Release() { LeaveCriticalSection(&cs); } void ContactAsyncQueue::RemoveAll(HANDLE hContact) { Lock(); for (int i = queue.getCount() - 1; i >= 0; --i) { QueueItem *item = queue[i]; if (item->hContact == hContact) { queue.remove(i); mir_free(item); } } Release(); } void ContactAsyncQueue::RemoveAllConsiderParam(HANDLE hContact, void *param) { Lock(); for (int i = queue.getCount() - 1; i >= 0; --i) { QueueItem *item = queue[i]; if (item->hContact == hContact && item->param == param) { queue.remove(i); mir_free(item); } } Release(); } void ContactAsyncQueue::Add(int waitTime, HANDLE hContact, void *param) { Lock(); InternalAdd(waitTime, hContact, param); Release(); } void ContactAsyncQueue::AddIfDontHave(int waitTime, HANDLE hContact, void *param) { Lock(); int i; for (i = queue.getCount() - 1; i >= 0; --i) if (queue[i]->hContact == hContact) break; if (i < 0) InternalAdd(waitTime, hContact, param); Release(); } void ContactAsyncQueue::AddAndRemovePrevious(int waitTime, HANDLE hContact, void *param) { Lock(); RemoveAll(hContact); InternalAdd(waitTime, hContact, param); Release(); } void ContactAsyncQueue::AddAndRemovePreviousConsiderParam(int waitTime, HANDLE hContact, void *param) { Lock(); RemoveAllConsiderParam(hContact, param); InternalAdd(waitTime, hContact, param); Release(); } void ContactAsyncQueue::InternalAdd(int waitTime, HANDLE hContact, void *param) { QueueItem *item = (QueueItem *) mir_alloc(sizeof(QueueItem)); item->hContact = hContact; item->check_time = GetTickCount() + waitTime; item->param = param; queue.insert(item); SetEvent(hEvent); } void ContactAsyncQueue::Thread() { while (!finished) { ResetEvent(hEvent); if (finished) break; Lock(); if (queue.getCount() <= 0) { // No items, so supend thread Release(); wait(/*INFINITE*/ 2 * 60 * 1000); } else { // Take a look at first item QueueItem *qi = queue[0]; int dt = qi->check_time - GetTickCount(); if (dt > 0) { // Not time to request yet, wait... Release(); wait(dt); } else { // Will request this item queue.remove(0); Release(); callback(qi->hContact, qi->param); mir_free(qi); } } } finished = 2; } void ContactAsyncQueue::wait(int time) { if (!finished) WaitForSingleObject(hEvent, time); }