diff options
Diffstat (limited to 'libparc/parc/algol/parc_Object.c')
-rw-r--r-- | libparc/parc/algol/parc_Object.c | 952 |
1 files changed, 952 insertions, 0 deletions
diff --git a/libparc/parc/algol/parc_Object.c b/libparc/parc/algol/parc_Object.c new file mode 100644 index 00000000..cd8acd45 --- /dev/null +++ b/libparc/parc/algol/parc_Object.c @@ -0,0 +1,952 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include <config.h> + +#include <LongBow/runtime.h> + +#include <stdio.h> +#include <inttypes.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/errno.h> +#include <pthread.h> +#include <time.h> +#include <sys/time.h> + +#include <stdint.h> +#include <stdbool.h> + +#include <parc/algol/parc_DisplayIndented.h> +#include <parc/algol/parc_Object.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_Hash.h> +#include <parc/concurrent/parc_AtomicUint64.h> + +typedef struct parc_object_locking { + pthread_mutex_t lock; + pthread_cond_t notification; + pthread_t locker; +} _PARCObjectLocking; + +/* + * This is the per-object header. + * The size of this structure must be less than or equal to the value used in the parcObject_PrefixLength macro. + */ +typedef struct object_header { +#define PARCObject_HEADER_MAGIC_GUARD_NUMBER 0x0ddFadda + uint32_t magicGuardNumber; + bool isAllocated; + bool barrier; + PARCReferenceCount references; + const PARCObjectDescriptor *descriptor; + + // The locking member points to the locking structure or is NULL if the object does not support locking. + _PARCObjectLocking *locking; + + // Currently every object is lockable, but at some point in the future this will be controlled by the descriptor. + _PARCObjectLocking lock; + + void *data[]; +} _PARCObjectHeader; + +/* + * Increment/decrement a pointer by the given value. + * + * @param [in] base The base pointer. + * @param [in] increment The value of the pointer increment. + * + * @return void* The updated pointer + */ +static inline void * +_pointerAdd(const void *base, const size_t increment) +{ + void *result = (void *) &((char *) base)[increment]; + return result; +} + +/* + * Compute the size of the prefix as the number of bytes necessary + * to fit the object header (with padding), and any additional per-object data, into allocated memory, + * such that the first address after the header and any additional per-object data, + * is aligned according to the value of the alignment parameter. + * + * For example, if the object header is 5 bytes long, and the alignment is 4 (bytes), + * then the necessary number of bytes to fit the header + * (and yet maintain the proper alignment for the first memory location after the header) is 8. + * + * @param [in] alignment Cache alignment + * + * @return The size of the object header as the number of bytes necessary to fit the header (with padding) into allocated memory. + */ +static inline size_t +_parcObject_PrefixLength(const PARCObjectDescriptor *descriptor) +{ + return parcObject_PrefixLength(descriptor->objectAlignment); +} + +/* + * Given the memory address, return a pointer to the corresponding _PARCObjectHeader structure. + * + * @param [in] object The base pointer to the object. + * + * @return A _PARCObjectHeader struct encapsulating the object's header information. + */ +static inline _PARCObjectHeader * +_parcObject_Header(const PARCObject *object) +{ + return _pointerAdd(object, -sizeof(_PARCObjectHeader)); +} + +static inline const PARCObjectDescriptor * +_parcObject_Descriptor(const PARCObject *object) +{ + return (_parcObject_Header(object)->descriptor); +} + +static inline _PARCObjectLocking * +_parcObjectHeader_Locking(const PARCObject *object) +{ + return _parcObject_Header(object)->locking; +} + +static inline bool +_parcObjectHeader_IsValid(const _PARCObjectHeader *header, const PARCObject *object) +{ + bool result = true; + + if ((intptr_t) header >= (intptr_t) object) { + result = false; + } else if (header->magicGuardNumber != PARCObject_HEADER_MAGIC_GUARD_NUMBER) { + result = false; + } else if (header->references == 0) { + result = false; + } + + return result; +} + +/* + * Compute the origin of the allocated memory. + * + * This will be greater than the start of the object header. + * due to alignment requirements causing the object header to be offset from the origin. + */ +static inline void * +_parcObject_Origin(const PARCObject *object) +{ + _PARCObjectHeader *header = _parcObject_Header(object); + + return _pointerAdd(object, -_parcObject_PrefixLength(header->descriptor)); +} + +static inline PARCObjectEquals * +_parcObject_ResolveEquals(const PARCObjectDescriptor *descriptor) +{ + while (descriptor->equals == NULL) { + descriptor = descriptor->super; + } + return descriptor->equals; +} + +static inline PARCObjectCopy * +_parcObject_ResolveCopy(const PARCObjectDescriptor *descriptor) +{ + while (descriptor->copy == NULL) { + descriptor = descriptor->super; + } + return descriptor->copy; +} + +static inline PARCObjectToString * +_parcObject_ResolveToString(const PARCObjectDescriptor *descriptor) +{ + while (descriptor->toString == NULL) { + descriptor = descriptor->super; + } + return descriptor->toString; +} + +static inline PARCObjectToJSON * +_parcObject_ResolveToJSON(const PARCObjectDescriptor *descriptor) +{ + while (descriptor->toJSON == NULL) { + descriptor = descriptor->super; + } + return descriptor->toJSON; +} + +static bool +_parcObject_Destructor(const PARCObjectDescriptor *descriptor, PARCObject **object) +{ + if (descriptor != NULL) { + if (descriptor->destructor != NULL) { + return descriptor->destructor(object); + } else if (descriptor->destroy != NULL) { + descriptor->destroy(object); + } + } + + return true; +} + +static int +_parcObject_Compare(const PARCObject *self, const PARCObject *other) +{ + _PARCObjectHeader *header = _parcObject_Header(self); + size_t length = header->descriptor->objectSize; + int result = memcmp(self, other, length); + return result; +} + +static PARCObject * +_parcObject_Copy(const PARCObject *object) +{ + _PARCObjectHeader *header = _parcObject_Header(object); + size_t length = header->descriptor->objectSize; + + void *result = parcObject_CreateInstanceImpl(header->descriptor); + memcpy(result, object, length); + parcObject_OptionalAssertValid(result); + return result; +} + +static bool +_parcObject_Equals(const PARCObject *x, const PARCObject *y) +{ + _PARCObjectHeader *header = _parcObject_Header(x); + + bool result = memcmp(x, y, header->descriptor->objectSize) == 0; + + return result; +} + +static char * +_parcObject_ToString(const PARCObject *object) +{ + _PARCObjectHeader *header = _parcObject_Header(object); + + char *string; + int nwritten = asprintf(&string, + "Object@%p { .references=%" PRId64 ", .objectLength = %zd, .objectAlignment=%u } data %p\n", + (void *) header, + header->references, header->descriptor->objectSize, header->descriptor->objectAlignment, object); + assertTrue(nwritten >= 0, "Error calling asprintf"); + char *result = parcMemory_StringDuplicate(string, strlen(string)); + free(string); + return result; +} + +static PARCJSON * +_parcObject_ToJSON(const PARCObject *object) +{ + _PARCObjectHeader *prefix = _parcObject_Header(object); + + PARCJSON *json = parcJSON_Create(); + + parcJSON_AddInteger(json, "references", prefix->references); + parcJSON_AddInteger(json, "objectLength", prefix->descriptor->objectSize); + parcJSON_AddInteger(json, "objectAlignment", prefix->descriptor->objectAlignment); + + char *addressString; + int nwritten = asprintf(&addressString, "%p", object); + assertTrue(nwritten >= 0, "Error calling asprintf"); + + parcJSON_AddString(json, "address", addressString); + + return json; +} + +static PARCHashCode +_parcObject_HashCode(const PARCObject *object) +{ + _PARCObjectHeader *header = _parcObject_Header(object); + return parcHashCode_Hash(object, header->descriptor->objectSize); +} + +static void +_parcObject_Display(const PARCObject *object, const int indentation) +{ + parcObject_OptionalAssertValid(object); + + _PARCObjectHeader *header = _parcObject_Header(object); + + parcDisplayIndented_PrintLine(indentation, "PARCObject@%p @%p={ .name=%s .references=%zd }\n", + object, header, header->descriptor->name, header->references); +} + +const PARCObjectDescriptor +parcObject_DescriptorName(PARCObject) = +{ + .name = "PARCObject", + .destroy = NULL, + .destructor = NULL, + .release = NULL, + .copy = _parcObject_Copy, + .toString = _parcObject_ToString, + .equals = _parcObject_Equals, + .compare = _parcObject_Compare, + .hashCode = _parcObject_HashCode, + .toJSON = _parcObject_ToJSON, + .display = _parcObject_Display, + .super = NULL, + .isLockable = true, + .objectSize = 0, + .objectAlignment = sizeof(void *) +}; + +bool +parcObject_IsValid(const PARCObject *object) +{ + bool result = true; + + if (object == NULL) { + result = false; + } else { + if (_parcObjectHeader_IsValid(_parcObject_Header(object), object) == false) { + result = false; + } + } + + return result; +} + +#ifdef PARCLibrary_DISABLE_VALIDATION +# define parcObjectHeader_OptionalAssertValid(_instance_) +#else +# define parcObjectHeader_OptionalAssertValid(_instance_) _parcObjectHeader_AssertValid(_instance_) +#endif + +static inline void +_parcObjectHeader_AssertValid(const _PARCObjectHeader *header, const PARCObject *object) +{ + trapIllegalValueIf(header->magicGuardNumber != PARCObject_HEADER_MAGIC_GUARD_NUMBER, "PARCObject@%p is corrupt.", object); + trapIllegalValueIf(header->descriptor == NULL, "PARCObject@%p descriptor cannot be NULL.", object); + if (header->descriptor->isLockable) { + trapIllegalValueIf(header->locking == NULL, "PARCObject@%p is corrupt. Is Lockable but no locking structure", object); + } +} + +static inline void +_parcObject_AssertValid(const PARCObject *object) +{ + trapIllegalValueIf(object == NULL, "PARCObject must be a non-null pointer."); + + _PARCObjectHeader *header = _parcObject_Header(object); + _parcObjectHeader_AssertValid(header, object); +} + +void +parcObject_AssertValid(const PARCObject *object) +{ + _parcObject_AssertValid(object); +} + +PARCObject * +parcObject_Acquire(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + _PARCObjectHeader *header = _parcObject_Header(object); + + parcAtomicUint64_Increment(&header->references); + + return (PARCObject *) object; +} + +static inline PARCObjectCompare * +_parcObject_ResolveCompare(const PARCObjectDescriptor *descriptor) +{ + while (descriptor->compare == NULL) { + descriptor = descriptor->super; + } + return descriptor->compare; +} + +int +parcObject_Compare(const PARCObject *x, const PARCObject *y) +{ + int result = 0; + if ((x == NULL) || (y == NULL)) { + result = 0; + if (x != NULL) { + result = 1; + } else if (y != NULL) { + result = -1; + } + return result; + } + + parcObject_OptionalAssertValid(x); + parcObject_OptionalAssertValid(y); + + PARCObjectCompare *compare = _parcObject_ResolveCompare(_parcObject_Descriptor(x)); + result = compare(x, y); + + return result; +} + +bool +parcObject_IsInstanceOf(const PARCObject *object, const PARCObjectDescriptor *descriptor) +{ + bool result = false; + + if (object != NULL) { + _PARCObjectHeader *header = _parcObject_Header(object); + + if (_parcObjectHeader_IsValid(header, object)) { + const PARCObjectDescriptor *d = _parcObject_Descriptor(object); + + while (result == false) { + if (d == descriptor) { + result = true; + } + d = d->super; + } + } + } + + return result; +} + +bool +parcObject_Equals(const PARCObject *x, const PARCObject *y) +{ + bool result = false; + + if (x == y) { + result = true; + } else if (x != NULL && y != NULL) { + _PARCObjectHeader *xHeader = _parcObject_Header(x); + _PARCObjectHeader *yHeader = _parcObject_Header(y); + + if (xHeader->descriptor == yHeader->descriptor) { + PARCObjectEquals *equals = _parcObject_ResolveEquals(xHeader->descriptor); + result = equals(x, y); + } + } + + return result; +} + +static inline PARCObjectHashCode * +_parcObject_ResolveHashCode(const PARCObjectDescriptor *descriptor) +{ + while (descriptor->hashCode == NULL) { + descriptor = descriptor->super; + } + return descriptor->hashCode; +} + +PARCHashCode +parcObject_HashCode(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + PARCObjectHashCode *hashCode = _parcObject_ResolveHashCode(_parcObject_Descriptor(object)); + + return hashCode(object); +} + +static inline PARCObjectDisplay * +_parcObject_ResolveDisplay(const PARCObjectDescriptor *descriptor) +{ + while (descriptor->display == NULL) { + descriptor = descriptor->super; + } + return descriptor->display; +} + +void +parcObject_Display(const PARCObject *object, const int indentation) +{ + parcObject_OptionalAssertValid(object); + + PARCObjectDisplay *display = _parcObject_ResolveDisplay(_parcObject_Descriptor(object)); + + display(object, indentation); +} + +char * +parcObject_ToString(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + PARCObjectToString *toString = _parcObject_ResolveToString(_parcObject_Descriptor(object)); + + return toString(object); +} + +PARCJSON * +parcObject_ToJSON(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + PARCObjectToJSON *toJSON = _parcObject_ResolveToJSON(_parcObject_Descriptor(object)); + return toJSON(object); +} + +PARCObject * +parcObject_CreateAndClearInstanceImpl(const PARCObjectDescriptor *descriptor) +{ + PARCObject *result = parcObject_CreateInstanceImpl(descriptor); + memset(result, 0, descriptor->objectSize); + return result; +} + +static pthread_once_t _parcObject_GlobalLockAttributesInitialized = PTHREAD_ONCE_INIT; +static pthread_mutexattr_t _parcObject_GlobalLockAttributes; + +static void +_parcObject_InitializeGobalLockAttributes(void) +{ + pthread_mutexattr_init(&_parcObject_GlobalLockAttributes); + pthread_mutexattr_settype(&_parcObject_GlobalLockAttributes, PTHREAD_MUTEX_ERRORCHECK); +} + +static inline void +_parcObject_InitializeLocking(_PARCObjectLocking *locking) +{ + if (locking != NULL) { + pthread_once(&_parcObject_GlobalLockAttributesInitialized, _parcObject_InitializeGobalLockAttributes); + + pthread_mutex_init(&locking->lock, &_parcObject_GlobalLockAttributes); + pthread_cond_init(&locking->notification, NULL); + + locking->locker = (pthread_t) NULL; + } +} + +static inline _PARCObjectHeader * +_parcObjectHeader_InitAllocated(_PARCObjectHeader *header, const PARCObjectDescriptor *descriptor) +{ + header->magicGuardNumber = PARCObject_HEADER_MAGIC_GUARD_NUMBER; + header->barrier = false; + header->references = 1; + header->descriptor = (PARCObjectDescriptor *) descriptor; + header->isAllocated = true; + + if (header->descriptor->isLockable) { + header->locking = &header->lock; + _parcObject_InitializeLocking(header->locking); + } else { + header->locking = NULL; + } + + return header; +} + +static inline _PARCObjectHeader * +_parcObjectHeader_InitUnallocated(_PARCObjectHeader *header, const PARCObjectDescriptor *descriptor) +{ + _parcObjectHeader_InitAllocated(header, descriptor); + header->isAllocated = false; + + return header; +} + +PARCObject * +parcObject_WrapImpl(void *memory, const PARCObjectDescriptor *descriptor) +{ + size_t prefixLength = _parcObject_PrefixLength(descriptor); + PARCObject *object = _pointerAdd(memory, prefixLength); + + _parcObjectHeader_InitUnallocated(_parcObject_Header(object), descriptor); + + return object; +} + +PARCObject * +parcObject_CreateInstanceImpl(const PARCObjectDescriptor *descriptor) +{ + size_t prefixLength = _parcObject_PrefixLength(descriptor); + size_t totalMemoryLength = prefixLength + descriptor->objectSize; + + void *origin = NULL; + parcMemory_MemAlign(&origin, sizeof(void *), totalMemoryLength); + + if (origin == NULL) { + errno = ENOMEM; + return NULL; + } + + PARCObject *object = _pointerAdd(origin, prefixLength); + + _parcObjectHeader_InitAllocated(_parcObject_Header(object), descriptor); + + errno = 0; + return object; +} + +PARCObject * +parcObject_InitInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor) +{ + _PARCObjectHeader *header = _parcObject_Header(object); + + _parcObjectHeader_InitUnallocated(header, descriptor); + return object; +} + +PARCObject * +parcObject_InitAndClearInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor) +{ + parcObject_InitInstanceImpl(object, descriptor); + + memset(object, 0, descriptor->objectSize); + return object; +} + +PARCObject * +parcObject_Copy(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + PARCObjectCopy *copy = _parcObject_ResolveCopy(_parcObject_Descriptor(object)); + return copy(object); +} + +PARCReferenceCount +parcObject_Release(PARCObject **objectPointer) +{ + PARCObject *object = *objectPointer; + parcObject_OptionalAssertValid(object); + + _PARCObjectHeader *header = _parcObject_Header(object); + + trapIllegalValueIf(header->references == 0, "PARCObject@%p references must be > 0", object); + + PARCReferenceCount result = parcAtomicUint64_Decrement(&header->references); + + if (result == 0) { + if (_parcObject_Destructor(header->descriptor, objectPointer)) { + if (header->locking != NULL) { + pthread_cond_destroy(&header->locking->notification); + } + if (header->isAllocated) { + void *origin = _parcObject_Origin(object); + parcMemory_Deallocate(&origin); + } + assertNotNull(*objectPointer, "Class implementation unnecessarily clears the object pointer."); + } else { + assertNull(*objectPointer, "Class implementation must clear the object pointer."); + } + } + + *objectPointer = NULL; + return result; +} + +PARCReferenceCount +parcObject_GetReferenceCount(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + _PARCObjectHeader *header = _parcObject_Header(object); + + return header->references; +} + +const PARCObjectDescriptor * +parcObject_GetDescriptor(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + _PARCObjectHeader *header = _parcObject_Header(object); + + return header->descriptor; +} + +const PARCObjectDescriptor * +parcObject_SetDescriptor(PARCObject *object, const PARCObjectDescriptor *descriptor) +{ + parcObject_OptionalAssertValid(object); + assertNotNull(descriptor, "PARCObjectDescriptor cannot be NULL."); + + _PARCObjectHeader *header = _parcObject_Header(object); + + const PARCObjectDescriptor *result = header->descriptor; + header->descriptor = (PARCObjectDescriptor *) descriptor; + + return result; +} + +PARCObjectDescriptor * +parcObjectDescriptor_Create(const char *name, + size_t objectSize, + unsigned int objectAlignment, + bool isLockable, + PARCObjectDestructor *destructor, + PARCObjectRelease *release, + PARCObjectCopy *copy, + PARCObjectToString *toString, + PARCObjectEquals *equals, + PARCObjectCompare *compare, + PARCObjectHashCode *hashCode, + PARCObjectToJSON *toJSON, + PARCObjectDisplay *display, + const PARCObjectDescriptor *superType, + PARCObjectTypeState *typeState) +{ + assertNotNull(superType, "Supertype descriptor cannot be NULL."); + + PARCObjectDescriptor *result = parcMemory_AllocateAndClear(sizeof(PARCObjectDescriptor)); + if (result != NULL) { + strncpy(result->name, name, sizeof(result->name) - 1); + result->name[sizeof(result->name) - 1] = 0; + result->destroy = NULL; + result->destructor = destructor; + result->release = release; + result->copy = copy; + result->toString = toString; + result->equals = equals; + result->compare = compare; + result->hashCode = hashCode; + result->toJSON = toJSON; + result->display = display; + result->super = superType; + result->objectSize = objectSize; + result->objectAlignment = objectAlignment; + result->typeState = typeState; + result->isLockable = isLockable; + } + return result; +} + +PARCObjectDescriptor * +parcObjectDescriptor_CreateExtension(const PARCObjectDescriptor *superType, const char *name) +{ + PARCObjectDescriptor *result = parcMemory_AllocateAndClear(sizeof(PARCObjectDescriptor)); + *result = *superType; + strncpy(result->name, name, sizeof(result->name) - 1); + result->name[sizeof(result->name) - 1] = 0; + return result; +} + +PARCObjectTypeState * +parcObjectDescriptor_GetTypeState(const PARCObjectDescriptor *descriptor) +{ + return descriptor->typeState; +} + +const PARCObjectDescriptor * +parcObjectDescriptor_GetSuperType(const PARCObjectDescriptor *descriptor) +{ + return descriptor->super; +} + +bool +parcObjectDescriptor_Destroy(PARCObjectDescriptor **descriptorPointer) +{ + parcMemory_Deallocate(descriptorPointer); + return true; +} + +bool +parcObject_Unlock(const PARCObject *object) +{ + bool result = false; + + parcObject_OptionalAssertValid(object); + + _PARCObjectHeader *header = _parcObject_Header(object); + if (header->references > 0) { + _parcObjectHeader_AssertValid(header, object); + + if (object != NULL) { + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + locking->locker = (pthread_t) NULL; + result = (pthread_mutex_unlock(&locking->lock) == 0); + + assertTrue(result, "Attempted to unlock an unowned lock."); + } + } + } + return result; +} + +bool +parcObject_Lock(const PARCObject *object) +{ +#ifndef _ANDROID_ + extern int errno; +#endif + bool result = false; + + parcObject_OptionalAssertValid(object); + + if (object != NULL) { + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + trapCannotObtainLockIf(pthread_equal(locking->locker, pthread_self()), + "Recursive locks on %p are not supported.", object); + + errno = pthread_mutex_lock(&locking->lock); + + if (errno == 0) { + locking->locker = pthread_self(); + result = true; + } + } + } + + return result; +} + +bool +parcObject_TryLock(const PARCObject *object) +{ + bool result = false; + + if (object != NULL) { + parcObject_OptionalAssertValid(object); + + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + trapCannotObtainLockIf(pthread_equal(locking->locker, pthread_self()), "Recursive locks are not supported."); + + int lockStatus = pthread_mutex_trylock(&locking->lock); + + if (lockStatus == 0) { + result = true; + locking->locker = pthread_self(); + } + } + } + + return result; +} + +bool +parcObject_IsLocked(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + bool result = false; + + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + result = locking->locker != (pthread_t) NULL; + } + + return result; +} + +void +parcObject_Wait(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + pthread_cond_wait(&locking->notification, &locking->lock); + } +} + +bool +parcObject_WaitUntil(const PARCObject *object, const struct timespec *time) +{ + parcObject_OptionalAssertValid(object); + + bool result = false; + + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + int waitResult = pthread_cond_timedwait(&locking->notification, &locking->lock, time); + if (waitResult == 0) { + result = true; + } + } + + return result; +} + +bool +parcObject_WaitFor(const PARCObject *object, const uint64_t nanoSeconds) +{ + parcObject_OptionalAssertValid(object); + + bool result = false; + + struct timeval now; + gettimeofday(&now, NULL); + + // Convert timeval to timespec. + struct timespec time = { + .tv_sec = now.tv_sec, + .tv_nsec = (now.tv_usec * 1000) + }; + time.tv_nsec += nanoSeconds; + time.tv_sec += time.tv_nsec / 1000000000; + time.tv_nsec = time.tv_nsec % 1000000000; + + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + int waitResult = pthread_cond_timedwait(&locking->notification, &locking->lock, &time); + + if (waitResult == 0) { + result = true; + } + } + + return result; +} + +void +parcObject_Notify(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + pthread_cond_signal(&locking->notification); + } +} + +void +parcObject_NotifyAll(const PARCObject *object) +{ + parcObject_OptionalAssertValid(object); + + _PARCObjectLocking *locking = _parcObjectHeader_Locking(object); + if (locking != NULL) { + pthread_cond_broadcast(&locking->notification); + } +} + +bool +parcObject_BarrierSet(const PARCObject *object) +{ + _PARCObjectHeader *header = _parcObject_Header(object); + + while (__sync_bool_compare_and_swap(&header->barrier, false, true) == false) { + ; + } + return true; +} + +bool +parcObject_BarrierUnset(const PARCObject *object) +{ + _PARCObjectHeader *header = _parcObject_Header(object); + + while (__sync_bool_compare_and_swap(&header->barrier, true, false) == false) { + ; + } + + return false; +} |