/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library 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 Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ #include #include #include #include #include #include #include #include "macros.h" /* * Status check macros */ #define goto_if_invalid_param_ntstatus(p, lbl) \ if ((p) == NULL) { \ status = STATUS_INVALID_PARAMETER; \ goto lbl; \ } #define goto_if_no_memory_ntstatus(p, lbl) \ if ((p) == NULL) { \ status = STATUS_NO_MEMORY; \ goto lbl; \ } #define goto_if_ntstatus_not_success(s, lbl) \ if ((s) != STATUS_SUCCESS) { \ status = s; \ goto lbl; \ } static NTSTATUS MemPtrNodeAppend(PtrList *list, PtrNode *node) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN bLocked = FALSE; goto_if_invalid_param_ntstatus(list, error); goto_if_invalid_param_ntstatus(node, error); LIBRPC_LOCK_MUTEX(bLocked, &list->mutex); node->next = node->prev = NULL; if (list->head == NULL) { /* This is the very first node */ list->head = node; list->tail = node; } else { /* Append the new node */ list->tail->next = node; node->prev = list->tail; list->tail = node; } list->count++; done: LIBRPC_UNLOCK_MUTEX(bLocked, &list->mutex); return status; error: goto done; } static NTSTATUS MemPtrNodeRemove(PtrList *list, PtrNode *node) { NTSTATUS status = STATUS_SUCCESS; goto_if_invalid_param_ntstatus(list, error); goto_if_invalid_param_ntstatus(node, error); /* We're assuming the list has already been locked */ if ((node == list->head) && (node == list->tail)) { list->head = list->tail = NULL; } else if (node == list->head) { list->head = node->next; list->head->prev = NULL; } else if (node == list->tail) { list->tail = node->prev; list->tail->next = NULL; } else { node->prev->next = node->next; node->next->prev = node->prev; } list->count--; done: return status; error: goto done; } NTSTATUS MemPtrListInit(PtrList **out) { NTSTATUS status = STATUS_SUCCESS; PtrList *list = NULL; goto_if_invalid_param_ntstatus(out, error); list = (PtrList*) malloc(sizeof(PtrList)); goto_if_no_memory_ntstatus(list, error); list->head = NULL; list->tail = NULL; list->count = 0; /* According to pthread_mutex_init(3) documentation the function call always succeeds */ pthread_mutex_init(&list->mutex, NULL); *out = list; done: return status; error: SAFE_FREE(list); *out = NULL; goto done; } NTSTATUS MemPtrListDestroy(PtrList **out) { NTSTATUS status = STATUS_SUCCESS; PtrList *list = NULL; PtrNode *node = NULL; int ret = 0; goto_if_invalid_param_ntstatus(out, done); list = *out; node = list->head; while (node) { PtrNode *rmnode = NULL; SAFE_FREE(node->ptr); rmnode = node; node = node->next; SAFE_FREE(rmnode); } ret = pthread_mutex_destroy(&list->mutex); if (ret) status = STATUS_UNSUCCESSFUL; SAFE_FREE(list); *out = NULL; done: return status; } NTSTATUS MemPtrAllocate(PtrList *list, void **out, size_t size, void *dep) { NTSTATUS status = STATUS_SUCCESS; PtrNode *node = NULL; goto_if_invalid_param_ntstatus(out, error); /* Allocate new node */ node = (PtrNode*) malloc(sizeof(PtrNode)); goto_if_no_memory_ntstatus(node, done); node->ptr = NULL; node->dep = dep; node->size = size; if (node->size) { /* Allocate the actual memory */ node->ptr = malloc(node->size); goto_if_no_memory_ntstatus(node->ptr, error); /* ... and initialise it to zero */ memset(node->ptr, 0, node->size); } status = MemPtrNodeAppend(list, node); goto_if_ntstatus_not_success(status, error); *out = node->ptr; done: return status; error: if (node && node->ptr) { SAFE_FREE(node->ptr); } SAFE_FREE(node); *out = NULL; goto done; } NTSTATUS MemPtrFree(PtrList *list, void *ptr) { NTSTATUS status = STATUS_SUCCESS; PtrNode *node = NULL; BOOLEAN bLocked = FALSE; goto_if_invalid_param_ntstatus(ptr, error); LIBRPC_LOCK_MUTEX(bLocked, &list->mutex); /* Free the pointer and all pointers (nodes) depending on it */ node = list->head; while (node) { if (node->dep == ptr || node->ptr == ptr) { PtrNode *rmnode = NULL; /* Move to the next node before removing the current one */ rmnode = node; node = node->next; status = MemPtrNodeRemove(list, rmnode); goto_if_ntstatus_not_success(status, error); free(rmnode->ptr); free(rmnode); continue; } node = node->next; } done: LIBRPC_UNLOCK_MUTEX(bLocked, &list->mutex); return status; error: goto done; } NTSTATUS MemPtrAddDependant(PtrList *list, void *ptr, void *dep) { NTSTATUS status = STATUS_SUCCESS; PtrNode *node = NULL; goto_if_invalid_param_ntstatus(ptr, error); /* Allocate new node */ node = (PtrNode*) malloc(sizeof(PtrNode)); goto_if_no_memory_ntstatus(node, done); node->ptr = ptr; node->dep = dep; node->size = 0; /* size is unknown when adding dependency */ status = MemPtrNodeAppend(list, node); goto_if_ntstatus_not_success(status, error); done: return status; error: /* Only the node should be freed here. node->ptr should be left intact */ SAFE_FREE(node); goto done; } /* local variables: mode: c c-basic-offset: 4 indent-tabs-mode: nil tab-width: 4 end: */