/** * Looking Glass * Copyright © 2017-2026 The Looking Glass Authors * https://looking-glass.io * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program 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 General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "com_ref.h" #include "common/debug.h" void comRef_initScope(unsigned size, ComScope ** instance, void *(allocFn)(size_t size), void (freeFn)(void * ptr), bool threadSafe) { ComScope * scope = *instance; const size_t ttlSize = sizeof(*scope) + sizeof(*(scope->refs)) * size; if (allocFn) scope = allocFn(ttlSize); DEBUG_ASSERT(scope && "No memory for scope"); memset(scope, 0, ttlSize); scope->threadSafe = threadSafe; if (threadSafe) LG_LOCK_INIT(scope->lock); scope->size = size; scope->refs = (typeof(scope->refs))(scope+1); scope->free = freeFn; *instance = scope; } void comRef_freeScope(ComScope ** instance) { if (!*instance) return; ComScope * scope = *instance; for(unsigned i = 0; i < scope->used; ++i) { typeof(scope->refs) ref = &scope->refs[i]; if (ref->ref) { ULONG count = IUnknown_Release(ref->ref); #ifdef DEBUG_COMREF if (count > 0 && scope->free) DEBUG_INFO("comRef %s release is %lu", ref->where, count); #else (void)count; #endif ref->ref = NULL; } } if (scope->threadSafe) LG_LOCK_FREE(scope->lock); if (scope->free) scope->free(scope); *instance = NULL; } IUnknown ** comRef_new(ComScope * scope, IUnknown *** dst, const char * where) { /* check if the value it points to is already in our memory range and if it * does, then reuse it */ if ((uintptr_t)*dst >= (uintptr_t)(scope->refs) && (uintptr_t)*dst < (uintptr_t)(scope->refs + scope->used)) { // if it already holds a value, release it before we overwrite if (**dst) { IUnknown_Release(**dst); **dst = NULL; } // return the existing member return *dst; } /* If you hit this, you need to enlarge the scope size, or check if you have a * resource leak. */ DEBUG_ASSERT(scope->used < scope->size && "ComRef Scope Full"); if (scope->threadSafe) LG_LOCK(scope->lock); typeof(scope->refs[0]) * ref = &scope->refs[scope->used]; ref->where = where; *dst = &ref->ref; ++scope->used; if (scope->threadSafe) LG_UNLOCK(scope->lock); return *dst; }