summaryrefslogtreecommitdiffstats
path: root/libparc/parc/concurrent
diff options
context:
space:
mode:
Diffstat (limited to 'libparc/parc/concurrent')
-rw-r--r--libparc/parc/concurrent/.gitignore5
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint16.c178
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint16.h341
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint32.c178
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint32.h341
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint64.c178
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint64.h341
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint8.c178
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint8.h341
-rwxr-xr-xlibparc/parc/concurrent/parc_FutureTask.c304
-rwxr-xr-xlibparc/parc/concurrent/parc_FutureTask.h657
-rwxr-xr-xlibparc/parc/concurrent/parc_Lock.c202
-rwxr-xr-xlibparc/parc/concurrent/parc_Lock.h377
-rwxr-xr-xlibparc/parc/concurrent/parc_Notifier.c149
-rwxr-xr-xlibparc/parc/concurrent/parc_Notifier.h178
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer.c75
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer.h162
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer_1x1.c235
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer_1x1.h143
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer_NxM.c167
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer_NxM.h146
-rwxr-xr-xlibparc/parc/concurrent/parc_ScheduledTask.c203
-rwxr-xr-xlibparc/parc/concurrent/parc_ScheduledTask.h467
-rw-r--r--libparc/parc/concurrent/parc_ScheduledThreadPool.c323
-rwxr-xr-xlibparc/parc/concurrent/parc_ScheduledThreadPool.h429
-rwxr-xr-xlibparc/parc/concurrent/parc_Synchronizer.c146
-rwxr-xr-xlibparc/parc/concurrent/parc_Synchronizer.h277
-rw-r--r--libparc/parc/concurrent/parc_Thread.c232
-rwxr-xr-xlibparc/parc/concurrent/parc_Thread.h601
-rw-r--r--libparc/parc/concurrent/parc_ThreadPool.c457
-rwxr-xr-xlibparc/parc/concurrent/parc_ThreadPool.h625
-rwxr-xr-xlibparc/parc/concurrent/parc_Timeout.c25
-rw-r--r--libparc/parc/concurrent/parc_Timeout.h141
-rwxr-xr-xlibparc/parc/concurrent/parc_Timer.c173
-rwxr-xr-xlibparc/parc/concurrent/parc_Timer.h431
-rw-r--r--libparc/parc/concurrent/test/.gitignore10
-rw-r--r--libparc/parc/concurrent/test/CMakeLists.txt25
-rw-r--r--libparc/parc/concurrent/test/test_parc_AtomicUint16.c361
-rw-r--r--libparc/parc/concurrent/test/test_parc_AtomicUint32.c361
-rw-r--r--libparc/parc/concurrent/test/test_parc_AtomicUint64.c361
-rw-r--r--libparc/parc/concurrent/test/test_parc_AtomicUint8.c361
-rw-r--r--libparc/parc/concurrent/test/test_parc_FutureTask.c317
-rw-r--r--libparc/parc/concurrent/test/test_parc_Lock.c352
-rwxr-xr-xlibparc/parc/concurrent/test/test_parc_Notifier.c267
-rwxr-xr-xlibparc/parc/concurrent/test/test_parc_RingBuffer_1x1.c325
-rwxr-xr-xlibparc/parc/concurrent/test/test_parc_RingBuffer_NxM.c106
-rw-r--r--libparc/parc/concurrent/test/test_parc_ScheduledTask.c244
-rw-r--r--libparc/parc/concurrent/test/test_parc_ScheduledThreadPool.c301
-rwxr-xr-xlibparc/parc/concurrent/test/test_parc_Synchronizer.c179
-rw-r--r--libparc/parc/concurrent/test/test_parc_Thread.c264
-rw-r--r--libparc/parc/concurrent/test/test_parc_ThreadPool.c273
-rw-r--r--libparc/parc/concurrent/test/test_parc_Timer.c213
52 files changed, 13726 insertions, 0 deletions
diff --git a/libparc/parc/concurrent/.gitignore b/libparc/parc/concurrent/.gitignore
new file mode 100644
index 00000000..e6ed7cc3
--- /dev/null
+++ b/libparc/parc/concurrent/.gitignore
@@ -0,0 +1,5 @@
+parcConcurrent_About.c
+parcConcurrent_About.h
+
+test/test_parc_RingBuffer_1x1
+test/test_parc_RingBuffer_NxM
diff --git a/libparc/parc/concurrent/parc_AtomicUint16.c b/libparc/parc/concurrent/parc_AtomicUint16.c
new file mode 100755
index 00000000..24c9f922
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint16.c
@@ -0,0 +1,178 @@
+/*
+ * 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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/concurrent/parc_AtomicUint16.h>
+
+struct PARCAtomicUint16 {
+ uint16_t value;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#endif
+};
+
+static void
+_parcAtomicUint16_Finalize(PARCAtomicUint16 **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCAtomicUint16 pointer.");
+
+ parcAtomicUint16_OptionalAssertValid((*instancePtr));
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcAtomicUint16, PARCAtomicUint16);
+
+parcObject_ImplementRelease(parcAtomicUint16, PARCAtomicUint16);
+
+parcObject_ExtendPARCObject(PARCAtomicUint16, _parcAtomicUint16_Finalize, parcAtomicUint16_Copy, NULL, parcAtomicUint16_Equals, parcAtomicUint16_Compare, parcAtomicUint16_HashCode, NULL);
+
+
+void
+parcAtomicUint16_AssertValid(const PARCAtomicUint16 *instance)
+{
+ assertTrue(parcAtomicUint16_IsValid(instance),
+ "PARCAtomicUint16 is not valid.");
+}
+
+PARCAtomicUint16 *
+parcAtomicUint16_Create(uint16_t value)
+{
+ PARCAtomicUint16 *result = parcObject_CreateAndClearInstance(PARCAtomicUint16);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+ result->value = value;
+#else
+ *result = value;
+#endif
+
+ return result;
+}
+
+int
+parcAtomicUint16_Compare(const PARCAtomicUint16 *instance, const PARCAtomicUint16 *other)
+{
+ int16_t comparison = parcAtomicUint16_GetValue(instance) - parcAtomicUint16_GetValue(other);
+
+ int result = 0;
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+
+ return result;
+}
+
+PARCAtomicUint16 *
+parcAtomicUint16_Copy(const PARCAtomicUint16 *original)
+{
+ PARCAtomicUint16 *result = parcAtomicUint16_Create(parcAtomicUint16_GetValue(original));
+
+ return result;
+}
+
+bool
+parcAtomicUint16_Equals(const PARCAtomicUint16 *x, const PARCAtomicUint16 *y)
+{
+ bool result = false;
+
+ result = parcAtomicUint16_GetValue(x) == parcAtomicUint16_GetValue(y);
+
+ return result;
+}
+
+PARCHashCode
+parcAtomicUint16_HashCode(const PARCAtomicUint16 *instance)
+{
+ PARCHashCode result = (PARCHashCode) parcAtomicUint16_GetValue(instance);
+
+ return result;
+}
+
+bool
+parcAtomicUint16_IsValid(const PARCAtomicUint16 *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+uint16_t
+parcAtomicUint16_GetValue(const PARCAtomicUint16 *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ return instance->value;
+#else
+ return *instance;
+#endif
+}
+
+uint16_t
+parcAtomicUint16_AddImpl(PARCAtomicUint16 *value, uint16_t addend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value += addend;
+ uint16_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_add_and_fetch(value, addend);
+#endif
+}
+
+uint16_t
+parcAtomicUint16_SubtractImpl(PARCAtomicUint16 *value, uint16_t subtrahend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value -= subtrahend;
+ uint16_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_sub_and_fetch(value, subtrahend);
+#endif
+}
+
+bool
+parcAtomicUint16_CompareAndSwapImpl(PARCAtomicUint16 *value, uint16_t predicate, uint16_t newValue)
+{
+ bool result = false;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ if (value->value == predicate) {
+ value->value = newValue;
+ result = true;
+ }
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ result = __sync_bool_compare_and_swap(value, predicate, newValue);
+#endif
+ return result;
+}
diff --git a/libparc/parc/concurrent/parc_AtomicUint16.h b/libparc/parc/concurrent/parc_AtomicUint16.h
new file mode 100755
index 00000000..ff6a4fc3
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint16.h
@@ -0,0 +1,341 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_AtomicUint16.h
+ * @ingroup threading
+ * @brief An atomically updated 16-bit unsigned integer.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_AtomicUint16
+#define PARCLibrary_parc_AtomicUint16
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+#include <pthread.h>
+struct PARCAtomicUint16;
+typedef struct PARCAtomicUint16 PARCAtomicUint16;
+#else
+typedef uint16_t PARCAtomicUint16;
+#endif
+
+
+PARCAtomicUint16 *parcAtomicInteger_CreateUint16(uint16_t value);
+
+uint16_t parcAtomicUint16_AddImpl(PARCAtomicUint16 *value, uint16_t addend);
+
+uint16_t parcAtomicUint16_SubtractImpl(PARCAtomicUint16 *value, uint16_t subtrahend);
+
+bool parcAtomicUint16_CompareAndSwapImpl(PARCAtomicUint16 *value, uint16_t predicate, uint16_t newValue);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+
+#define parcAtomicUint16_Add parcAtomicUint16_AddImpl
+
+#define parcAtomicUint16_Subtract parcAtomicUint16_SubtractImpl
+
+#define parcAtomicUint16_CompareAndSwap parcAtomicUint16_CompareAndSwapImpl
+
+#else
+
+#define parcAtomicUint16_Add(_atomic_uint16_, _addend_) \
+ __sync_add_and_fetch(_atomic_uint16_, _addend_)
+
+#define parcAtomicUint16_Subtract(_atomic_uint16_, _subtrahend_) \
+ __sync_sub_and_fetch(_atomic_uint16_, _subtrahend_)
+
+#define parcAtomicUint16_CompareAndSwap(_atomic_uint16_, _predicate_, _newValue_) \
+ __sync_bool_compare_and_swap(_atomic_uint16_, _predicate_, _newValue_)
+#endif
+
+#define parcAtomicUint16_Increment(_atomic_uint16_) parcAtomicUint16_Add(_atomic_uint16_, 1)
+#define parcAtomicUint16_Decrement(_atomic_uint16_) parcAtomicUint16_Subtract(_atomic_uint16_, 1)
+
+/**
+ * Increase the number of references to a `PARCAtomicUint16` instance.
+ *
+ * Note that new `PARCAtomicUint16` is not created,
+ * only that the given `PARCAtomicUint16` reference count is incremented.
+ * Discard the reference by invoking `parcAtomicUint16_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * PARCAtomicUint16 *b = parcAtomicUint16_Acquire();
+ *
+ * parcAtomicUint16_Release(&a);
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint16 *parcAtomicUint16_Acquire(const PARCAtomicUint16 *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcAtomicUint16_OptionalAssertValid(_instance_)
+#else
+# define parcAtomicUint16_OptionalAssertValid(_instance_) parcAtomicUint16_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCAtomicUint16` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * parcAtomicUint16_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ */
+void parcAtomicUint16_AssertValid(const PARCAtomicUint16 *instance);
+
+/**
+ * Create an instance of PARCAtomicUint16
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCAtomicUint16 instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint16 *parcAtomicUint16_Create(uint16_t);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint16 instance.
+ * @param [in] other A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ * PARCAtomicUint16 *b = parcAtomicUint16_Create();
+ *
+ * if (parcAtomicUint16_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint16_Release(&a);
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcAtomicUint16_Equals
+ */
+int parcAtomicUint16_Compare(const PARCAtomicUint16 *instance, const PARCAtomicUint16 *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCAtomicUint16` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * PARCAtomicUint16 *copy = parcAtomicUint16_Copy(&b);
+ *
+ * parcAtomicUint16_Release(&b);
+ * parcAtomicUint16_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCAtomicUint16 *parcAtomicUint16_Copy(const PARCAtomicUint16 *original);
+
+/**
+ * Determine if two `PARCAtomicUint16` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCAtomicUint16` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcAtomicUint16_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcAtomicUint16_Equals(x, y)` must return true if and only if
+ * `parcAtomicUint16_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcAtomicUint16_Equals(x, y)` returns true and
+ * `parcAtomicUint16_Equals(y, z)` returns true,
+ * then `parcAtomicUint16_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcAtomicUint16_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcAtomicUint16_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCAtomicUint16 instance.
+ * @param [in] y A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ * PARCAtomicUint16 *b = parcAtomicUint16_Create();
+ *
+ * if (parcAtomicUint16_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint16_Release(&a);
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ * @see parcAtomicUint16_HashCode
+ */
+bool parcAtomicUint16_Equals(const PARCAtomicUint16 *x, const PARCAtomicUint16 *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcAtomicUint16_Equals} method,
+ * then calling the {@link parcAtomicUint16_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcAtomicUint16_Equals} function,
+ * then calling the `parcAtomicUint16_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * PARCHashCode hashValue = parcAtomicUint16_HashCode(buffer);
+ * parcAtomicUint16_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcAtomicUint16_HashCode(const PARCAtomicUint16 *instance);
+
+/**
+ * Determine if an instance of `PARCAtomicUint16` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * if (parcAtomicUint16_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcAtomicUint16_IsValid(const PARCAtomicUint16 *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCAtomicUint16` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * parcAtomicUint16_Release(&a);
+ * }
+ * @endcode
+ */
+void parcAtomicUint16_Release(PARCAtomicUint16 **instancePtr);
+
+/**
+ * Get the current value of the given `PARCAtomicUint16` instance.
+ *
+ * @param [in] instance A pointer to a valid `PARCAtomicUint16` instance.
+ *
+ * @return the current value of the given `PARCAtomicUint16` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ *
+ * uint16_t value = parcAtomicUint16_GetValue(instance);
+ *
+ * parcAtomicUint16_Release(&instance);
+ * }
+ * @endcode
+ */
+uint16_t parcAtomicUint16_GetValue(const PARCAtomicUint16 *instance);
+#endif
diff --git a/libparc/parc/concurrent/parc_AtomicUint32.c b/libparc/parc/concurrent/parc_AtomicUint32.c
new file mode 100755
index 00000000..32ed7a6a
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint32.c
@@ -0,0 +1,178 @@
+/*
+ * 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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/concurrent/parc_AtomicUint32.h>
+
+struct PARCAtomicUint32 {
+ uint32_t value;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#endif
+};
+
+static void
+_parcAtomicUint32_Finalize(PARCAtomicUint32 **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCAtomicUint32 pointer.");
+
+ parcAtomicUint32_OptionalAssertValid((*instancePtr));
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcAtomicUint32, PARCAtomicUint32);
+
+parcObject_ImplementRelease(parcAtomicUint32, PARCAtomicUint32);
+
+parcObject_ExtendPARCObject(PARCAtomicUint32, _parcAtomicUint32_Finalize, parcAtomicUint32_Copy, NULL, parcAtomicUint32_Equals, parcAtomicUint32_Compare, parcAtomicUint32_HashCode, NULL);
+
+
+void
+parcAtomicUint32_AssertValid(const PARCAtomicUint32 *instance)
+{
+ assertTrue(parcAtomicUint32_IsValid(instance),
+ "PARCAtomicUint32 is not valid.");
+}
+
+PARCAtomicUint32 *
+parcAtomicUint32_Create(uint32_t value)
+{
+ PARCAtomicUint32 *result = parcObject_CreateAndClearInstance(PARCAtomicUint32);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+ result->value = value;
+#else
+ *result = value;
+#endif
+
+ return result;
+}
+
+int
+parcAtomicUint32_Compare(const PARCAtomicUint32 *instance, const PARCAtomicUint32 *other)
+{
+ int32_t comparison = parcAtomicUint32_GetValue(instance) - parcAtomicUint32_GetValue(other);
+
+ int result = 0;
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+
+ return result;
+}
+
+PARCAtomicUint32 *
+parcAtomicUint32_Copy(const PARCAtomicUint32 *original)
+{
+ PARCAtomicUint32 *result = parcAtomicUint32_Create(parcAtomicUint32_GetValue(original));
+
+ return result;
+}
+
+bool
+parcAtomicUint32_Equals(const PARCAtomicUint32 *x, const PARCAtomicUint32 *y)
+{
+ bool result = false;
+
+ result = parcAtomicUint32_GetValue(x) == parcAtomicUint32_GetValue(y);
+
+ return result;
+}
+
+PARCHashCode
+parcAtomicUint32_HashCode(const PARCAtomicUint32 *instance)
+{
+ PARCHashCode result = (PARCHashCode) parcAtomicUint32_GetValue(instance);
+
+ return result;
+}
+
+bool
+parcAtomicUint32_IsValid(const PARCAtomicUint32 *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+uint32_t
+parcAtomicUint32_GetValue(const PARCAtomicUint32 *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ return instance->value;
+#else
+ return *instance;
+#endif
+}
+
+uint32_t
+parcAtomicUint32_AddImpl(PARCAtomicUint32 *value, uint32_t addend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value += addend;
+ uint32_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_add_and_fetch(value, addend);
+#endif
+}
+
+uint32_t
+parcAtomicUint32_SubtractImpl(PARCAtomicUint32 *value, uint32_t subtrahend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value -= subtrahend;
+ uint32_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_sub_and_fetch(value, subtrahend);
+#endif
+}
+
+bool
+parcAtomicUint32_CompareAndSwapImpl(PARCAtomicUint32 *value, uint32_t predicate, uint32_t newValue)
+{
+ bool result = false;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ if (value->value == predicate) {
+ value->value = newValue;
+ result = true;
+ }
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ result = __sync_bool_compare_and_swap(value, predicate, newValue);
+#endif
+ return result;
+}
diff --git a/libparc/parc/concurrent/parc_AtomicUint32.h b/libparc/parc/concurrent/parc_AtomicUint32.h
new file mode 100755
index 00000000..870cbe80
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint32.h
@@ -0,0 +1,341 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_AtomicUint32.h
+ * @ingroup threading
+ * @brief An atomically updated 32-bit unsigned integer.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_AtomicUint32
+#define PARCLibrary_parc_AtomicUint32
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+#include <pthread.h>
+struct PARCAtomicUint32;
+typedef struct PARCAtomicUint32 PARCAtomicUint32;
+#else
+typedef uint32_t PARCAtomicUint32;
+#endif
+
+
+PARCAtomicUint32 *parcAtomicInteger_CreateUint32(uint32_t value);
+
+uint32_t parcAtomicUint32_AddImpl(PARCAtomicUint32 *value, uint32_t addend);
+
+uint32_t parcAtomicUint32_SubtractImpl(PARCAtomicUint32 *value, uint32_t subtrahend);
+
+bool parcAtomicUint32_CompareAndSwapImpl(PARCAtomicUint32 *value, uint32_t predicate, uint32_t newValue);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+
+#define parcAtomicUint32_Add parcAtomicUint32_AddImpl
+
+#define parcAtomicUint32_Subtract parcAtomicUint32_SubtractImpl
+
+#define parcAtomicUint32_CompareAndSwap parcAtomicUint32_CompareAndSwapImpl
+
+#else
+
+#define parcAtomicUint32_Add(_atomic_uint32_, _addend_) \
+ __sync_add_and_fetch(_atomic_uint32_, _addend_)
+
+#define parcAtomicUint32_Subtract(_atomic_uint32_, _subtrahend_) \
+ __sync_sub_and_fetch(_atomic_uint32_, _subtrahend_)
+
+#define parcAtomicUint32_CompareAndSwap(_atomic_uint32_, _predicate_, _newValue_) \
+ __sync_bool_compare_and_swap(_atomic_uint32_, _predicate_, _newValue_)
+#endif
+
+#define parcAtomicUint32_Increment(_atomic_uint32_) parcAtomicUint32_Add(_atomic_uint32_, 1)
+#define parcAtomicUint32_Decrement(_atomic_uint32_) parcAtomicUint32_Subtract(_atomic_uint32_, 1)
+
+/**
+ * Increase the number of references to a `PARCAtomicUint32` instance.
+ *
+ * Note that new `PARCAtomicUint32` is not created,
+ * only that the given `PARCAtomicUint32` reference count is incremented.
+ * Discard the reference by invoking `parcAtomicUint32_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * PARCAtomicUint32 *b = parcAtomicUint32_Acquire();
+ *
+ * parcAtomicUint32_Release(&a);
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint32 *parcAtomicUint32_Acquire(const PARCAtomicUint32 *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcAtomicUint32_OptionalAssertValid(_instance_)
+#else
+# define parcAtomicUint32_OptionalAssertValid(_instance_) parcAtomicUint32_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCAtomicUint32` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * parcAtomicUint32_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ */
+void parcAtomicUint32_AssertValid(const PARCAtomicUint32 *instance);
+
+/**
+ * Create an instance of PARCAtomicUint32
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCAtomicUint32 instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint32 *parcAtomicUint32_Create(uint32_t);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint32 instance.
+ * @param [in] other A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ * PARCAtomicUint32 *b = parcAtomicUint32_Create();
+ *
+ * if (parcAtomicUint32_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint32_Release(&a);
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcAtomicUint32_Equals
+ */
+int parcAtomicUint32_Compare(const PARCAtomicUint32 *instance, const PARCAtomicUint32 *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCAtomicUint32` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * PARCAtomicUint32 *copy = parcAtomicUint32_Copy(&b);
+ *
+ * parcAtomicUint32_Release(&b);
+ * parcAtomicUint32_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCAtomicUint32 *parcAtomicUint32_Copy(const PARCAtomicUint32 *original);
+
+/**
+ * Determine if two `PARCAtomicUint32` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCAtomicUint32` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcAtomicUint32_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcAtomicUint32_Equals(x, y)` must return true if and only if
+ * `parcAtomicUint32_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcAtomicUint32_Equals(x, y)` returns true and
+ * `parcAtomicUint32_Equals(y, z)` returns true,
+ * then `parcAtomicUint32_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcAtomicUint32_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcAtomicUint32_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCAtomicUint32 instance.
+ * @param [in] y A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ * PARCAtomicUint32 *b = parcAtomicUint32_Create();
+ *
+ * if (parcAtomicUint32_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint32_Release(&a);
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ * @see parcAtomicUint32_HashCode
+ */
+bool parcAtomicUint32_Equals(const PARCAtomicUint32 *x, const PARCAtomicUint32 *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcAtomicUint32_Equals} method,
+ * then calling the {@link parcAtomicUint32_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcAtomicUint32_Equals} function,
+ * then calling the `parcAtomicUint32_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * PARCHashCode hashValue = parcAtomicUint32_HashCode(buffer);
+ * parcAtomicUint32_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcAtomicUint32_HashCode(const PARCAtomicUint32 *instance);
+
+/**
+ * Determine if an instance of `PARCAtomicUint32` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * if (parcAtomicUint32_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcAtomicUint32_IsValid(const PARCAtomicUint32 *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCAtomicUint32` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * parcAtomicUint32_Release(&a);
+ * }
+ * @endcode
+ */
+void parcAtomicUint32_Release(PARCAtomicUint32 **instancePtr);
+
+/**
+ * Get the current value of the given `PARCAtomicUint32` instance.
+ *
+ * @param [in] instance A pointer to a valid `PARCAtomicUint32` instance.
+ *
+ * @return the current value of the given `PARCAtomicUint32` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *instance = parcAtomicUint32_Create(7);
+ *
+ * uint32_t value = parcAtomicUint32_GetValue(instance);
+ *
+ * parcAtomicUint32_Release(&instance);
+ * }
+ * @endcode
+ */
+uint32_t parcAtomicUint32_GetValue(const PARCAtomicUint32 *instance);
+#endif
diff --git a/libparc/parc/concurrent/parc_AtomicUint64.c b/libparc/parc/concurrent/parc_AtomicUint64.c
new file mode 100755
index 00000000..35d5cf66
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint64.c
@@ -0,0 +1,178 @@
+/*
+ * 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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/concurrent/parc_AtomicUint64.h>
+
+struct PARCAtomicUint64 {
+ uint64_t value;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#endif
+};
+
+static void
+_parcAtomicUint64_Finalize(PARCAtomicUint64 **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCAtomicUint64 pointer.");
+
+ parcAtomicUint64_OptionalAssertValid((*instancePtr));
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcAtomicUint64, PARCAtomicUint64);
+
+parcObject_ImplementRelease(parcAtomicUint64, PARCAtomicUint64);
+
+parcObject_ExtendPARCObject(PARCAtomicUint64, _parcAtomicUint64_Finalize, parcAtomicUint64_Copy, NULL, parcAtomicUint64_Equals, parcAtomicUint64_Compare, parcAtomicUint64_HashCode, NULL);
+
+
+void
+parcAtomicUint64_AssertValid(const PARCAtomicUint64 *instance)
+{
+ assertTrue(parcAtomicUint64_IsValid(instance),
+ "PARCAtomicUint64 is not valid.");
+}
+
+PARCAtomicUint64 *
+parcAtomicUint64_Create(uint64_t value)
+{
+ PARCAtomicUint64 *result = parcObject_CreateAndClearInstance(PARCAtomicUint64);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+ result->value = value;
+#else
+ *result = value;
+#endif
+
+ return result;
+}
+
+int
+parcAtomicUint64_Compare(const PARCAtomicUint64 *instance, const PARCAtomicUint64 *other)
+{
+ int64_t comparison = parcAtomicUint64_GetValue(instance) - parcAtomicUint64_GetValue(other);
+
+ int result = 0;
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+
+ return result;
+}
+
+PARCAtomicUint64 *
+parcAtomicUint64_Copy(const PARCAtomicUint64 *original)
+{
+ PARCAtomicUint64 *result = parcAtomicUint64_Create(parcAtomicUint64_GetValue(original));
+
+ return result;
+}
+
+bool
+parcAtomicUint64_Equals(const PARCAtomicUint64 *x, const PARCAtomicUint64 *y)
+{
+ bool result = false;
+
+ result = parcAtomicUint64_GetValue(x) == parcAtomicUint64_GetValue(y);
+
+ return result;
+}
+
+PARCHashCode
+parcAtomicUint64_HashCode(const PARCAtomicUint64 *instance)
+{
+ PARCHashCode result = (PARCHashCode) parcAtomicUint64_GetValue(instance);
+
+ return result;
+}
+
+bool
+parcAtomicUint64_IsValid(const PARCAtomicUint64 *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+uint64_t
+parcAtomicUint64_GetValue(const PARCAtomicUint64 *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ return instance->value;
+#else
+ return *instance;
+#endif
+}
+
+uint64_t
+parcAtomicUint64_AddImpl(PARCAtomicUint64 *value, uint64_t addend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value += addend;
+ uint64_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_add_and_fetch(value, addend);
+#endif
+}
+
+uint64_t
+parcAtomicUint64_SubtractImpl(PARCAtomicUint64 *value, uint64_t subtrahend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value -= subtrahend;
+ uint64_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_sub_and_fetch(value, subtrahend);
+#endif
+}
+
+bool
+parcAtomicUint64_CompareAndSwapImpl(PARCAtomicUint64 *value, uint64_t predicate, uint64_t newValue)
+{
+ bool result = false;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ if (value->value == predicate) {
+ value->value = newValue;
+ result = true;
+ }
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ result = __sync_bool_compare_and_swap(value, predicate, newValue);
+#endif
+ return result;
+}
diff --git a/libparc/parc/concurrent/parc_AtomicUint64.h b/libparc/parc/concurrent/parc_AtomicUint64.h
new file mode 100755
index 00000000..a6ac3ec1
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint64.h
@@ -0,0 +1,341 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_AtomicUint64.h
+ * @ingroup threading
+ * @brief An atomically updated 64-bit unsigned integer.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_AtomicUint64
+#define PARCLibrary_parc_AtomicUint64
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+#include <pthread.h>
+struct PARCAtomicUint64;
+typedef struct PARCAtomicUint64 PARCAtomicUint64;
+#else
+typedef uint64_t PARCAtomicUint64;
+#endif
+
+
+PARCAtomicUint64 *parcAtomicInteger_CreateUint64(uint64_t value);
+
+uint64_t parcAtomicUint64_AddImpl(PARCAtomicUint64 *value, uint64_t addend);
+
+uint64_t parcAtomicUint64_SubtractImpl(PARCAtomicUint64 *value, uint64_t subtrahend);
+
+bool parcAtomicUint64_CompareAndSwapImpl(PARCAtomicUint64 *value, uint64_t predicate, uint64_t newValue);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+
+#define parcAtomicUint64_Add parcAtomicUint64_AddImpl
+
+#define parcAtomicUint64_Subtract parcAtomicUint64_SubtractImpl
+
+#define parcAtomicUint64_CompareAndSwap parcAtomicUint64_CompareAndSwapImpl
+
+#else
+
+#define parcAtomicUint64_Add(_atomic_uint64_, _addend_) \
+ __sync_add_and_fetch(_atomic_uint64_, _addend_)
+
+#define parcAtomicUint64_Subtract(_atomic_uint64_, _subtrahend_) \
+ __sync_sub_and_fetch(_atomic_uint64_, _subtrahend_)
+
+#define parcAtomicUint64_CompareAndSwap(_atomic_uint64_, _predicate_, _newValue_) \
+ __sync_bool_compare_and_swap(_atomic_uint64_, _predicate_, _newValue_)
+#endif
+
+#define parcAtomicUint64_Increment(_atomic_uint64_) parcAtomicUint64_Add(_atomic_uint64_, 1)
+#define parcAtomicUint64_Decrement(_atomic_uint64_) parcAtomicUint64_Subtract(_atomic_uint64_, 1)
+
+/**
+ * Increase the number of references to a `PARCAtomicUint64` instance.
+ *
+ * Note that new `PARCAtomicUint64` is not created,
+ * only that the given `PARCAtomicUint64` reference count is incremented.
+ * Discard the reference by invoking `parcAtomicUint64_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * PARCAtomicUint64 *b = parcAtomicUint64_Acquire();
+ *
+ * parcAtomicUint64_Release(&a);
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint64 *parcAtomicUint64_Acquire(const PARCAtomicUint64 *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcAtomicUint64_OptionalAssertValid(_instance_)
+#else
+# define parcAtomicUint64_OptionalAssertValid(_instance_) parcAtomicUint64_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCAtomicUint64` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * parcAtomicUint64_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ */
+void parcAtomicUint64_AssertValid(const PARCAtomicUint64 *instance);
+
+/**
+ * Create an instance of PARCAtomicUint64
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCAtomicUint64 instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint64 *parcAtomicUint64_Create(uint64_t);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint64 instance.
+ * @param [in] other A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ * PARCAtomicUint64 *b = parcAtomicUint64_Create();
+ *
+ * if (parcAtomicUint64_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint64_Release(&a);
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcAtomicUint64_Equals
+ */
+int parcAtomicUint64_Compare(const PARCAtomicUint64 *instance, const PARCAtomicUint64 *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCAtomicUint64` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * PARCAtomicUint64 *copy = parcAtomicUint64_Copy(&b);
+ *
+ * parcAtomicUint64_Release(&b);
+ * parcAtomicUint64_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCAtomicUint64 *parcAtomicUint64_Copy(const PARCAtomicUint64 *original);
+
+/**
+ * Determine if two `PARCAtomicUint64` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCAtomicUint64` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcAtomicUint64_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcAtomicUint64_Equals(x, y)` must return true if and only if
+ * `parcAtomicUint64_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcAtomicUint64_Equals(x, y)` returns true and
+ * `parcAtomicUint64_Equals(y, z)` returns true,
+ * then `parcAtomicUint64_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcAtomicUint64_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcAtomicUint64_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCAtomicUint64 instance.
+ * @param [in] y A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ * PARCAtomicUint64 *b = parcAtomicUint64_Create();
+ *
+ * if (parcAtomicUint64_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint64_Release(&a);
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ * @see parcAtomicUint64_HashCode
+ */
+bool parcAtomicUint64_Equals(const PARCAtomicUint64 *x, const PARCAtomicUint64 *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcAtomicUint64_Equals} method,
+ * then calling the {@link parcAtomicUint64_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcAtomicUint64_Equals} function,
+ * then calling the `parcAtomicUint64_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * PARCHashCode hashValue = parcAtomicUint64_HashCode(buffer);
+ * parcAtomicUint64_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcAtomicUint64_HashCode(const PARCAtomicUint64 *instance);
+
+/**
+ * Determine if an instance of `PARCAtomicUint64` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * if (parcAtomicUint64_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcAtomicUint64_IsValid(const PARCAtomicUint64 *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCAtomicUint64` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * parcAtomicUint64_Release(&a);
+ * }
+ * @endcode
+ */
+void parcAtomicUint64_Release(PARCAtomicUint64 **instancePtr);
+
+/**
+ * Get the current value of the given `PARCAtomicUint64` instance.
+ *
+ * @param [in] instance A pointer to a valid `PARCAtomicUint64` instance.
+ *
+ * @return the current value of the given `PARCAtomicUint64` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ *
+ * uint64_t value = parcAtomicUint64_GetValue(instance);
+ *
+ * parcAtomicUint64_Release(&instance);
+ * }
+ * @endcode
+ */
+uint64_t parcAtomicUint64_GetValue(const PARCAtomicUint64 *instance);
+#endif
diff --git a/libparc/parc/concurrent/parc_AtomicUint8.c b/libparc/parc/concurrent/parc_AtomicUint8.c
new file mode 100755
index 00000000..59a3d865
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint8.c
@@ -0,0 +1,178 @@
+/*
+ * 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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/concurrent/parc_AtomicUint8.h>
+
+struct PARCAtomicUint8 {
+ uint8_t value;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#endif
+};
+
+static void
+_parcAtomicUint8_Finalize(PARCAtomicUint8 **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCAtomicUint8 pointer.");
+
+ parcAtomicUint8_OptionalAssertValid((*instancePtr));
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcAtomicUint8, PARCAtomicUint8);
+
+parcObject_ImplementRelease(parcAtomicUint8, PARCAtomicUint8);
+
+parcObject_ExtendPARCObject(PARCAtomicUint8, _parcAtomicUint8_Finalize, parcAtomicUint8_Copy, NULL, parcAtomicUint8_Equals, parcAtomicUint8_Compare, parcAtomicUint8_HashCode, NULL);
+
+
+void
+parcAtomicUint8_AssertValid(const PARCAtomicUint8 *instance)
+{
+ assertTrue(parcAtomicUint8_IsValid(instance),
+ "PARCAtomicUint8 is not valid.");
+}
+
+PARCAtomicUint8 *
+parcAtomicUint8_Create(uint8_t value)
+{
+ PARCAtomicUint8 *result = parcObject_CreateAndClearInstance(PARCAtomicUint8);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+ result->value = value;
+#else
+ *result = value;
+#endif
+
+ return result;
+}
+
+int
+parcAtomicUint8_Compare(const PARCAtomicUint8 *instance, const PARCAtomicUint8 *other)
+{
+ int8_t comparison = parcAtomicUint8_GetValue(instance) - parcAtomicUint8_GetValue(other);
+
+ int result = 0;
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+
+ return result;
+}
+
+PARCAtomicUint8 *
+parcAtomicUint8_Copy(const PARCAtomicUint8 *original)
+{
+ PARCAtomicUint8 *result = parcAtomicUint8_Create(parcAtomicUint8_GetValue(original));
+
+ return result;
+}
+
+bool
+parcAtomicUint8_Equals(const PARCAtomicUint8 *x, const PARCAtomicUint8 *y)
+{
+ bool result = false;
+
+ result = parcAtomicUint8_GetValue(x) == parcAtomicUint8_GetValue(y);
+
+ return result;
+}
+
+PARCHashCode
+parcAtomicUint8_HashCode(const PARCAtomicUint8 *instance)
+{
+ PARCHashCode result = (uint32_t) parcAtomicUint8_GetValue(instance);
+
+ return result;
+}
+
+bool
+parcAtomicUint8_IsValid(const PARCAtomicUint8 *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+uint8_t
+parcAtomicUint8_GetValue(const PARCAtomicUint8 *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ return instance->value;
+#else
+ return *instance;
+#endif
+}
+
+uint8_t
+parcAtomicUint8_AddImpl(PARCAtomicUint8 *value, uint8_t addend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value += addend;
+ uint8_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_add_and_fetch(value, addend);
+#endif
+}
+
+uint8_t
+parcAtomicUint8_SubtractImpl(PARCAtomicUint8 *value, uint8_t subtrahend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value -= subtrahend;
+ uint8_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_sub_and_fetch(value, subtrahend);
+#endif
+}
+
+bool
+parcAtomicUint8_CompareAndSwapImpl(PARCAtomicUint8 *value, uint8_t predicate, uint8_t newValue)
+{
+ bool result = false;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ if (value->value == predicate) {
+ value->value = newValue;
+ result = true;
+ }
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ result = __sync_bool_compare_and_swap(value, predicate, newValue);
+#endif
+ return result;
+}
diff --git a/libparc/parc/concurrent/parc_AtomicUint8.h b/libparc/parc/concurrent/parc_AtomicUint8.h
new file mode 100755
index 00000000..7434b93d
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint8.h
@@ -0,0 +1,341 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_AtomicUint8.h
+ * @ingroup threading
+ * @brief An atomically updated 8-bit unsigned integer.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_AtomicUint8
+#define PARCLibrary_parc_AtomicUint8
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+#include <pthread.h>
+struct PARCAtomicUint8;
+typedef struct PARCAtomicUint8 PARCAtomicUint8;
+#else
+typedef uint8_t PARCAtomicUint8;
+#endif
+
+
+PARCAtomicUint8 *parcAtomicInteger_CreateUint8(uint8_t value);
+
+uint8_t parcAtomicUint8_AddImpl(PARCAtomicUint8 *value, uint8_t addend);
+
+uint8_t parcAtomicUint8_SubtractImpl(PARCAtomicUint8 *value, uint8_t subtrahend);
+
+bool parcAtomicUint8_CompareAndSwapImpl(PARCAtomicUint8 *value, uint8_t predicate, uint8_t newValue);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+
+#define parcAtomicUint8_Add parcAtomicUint8_AddImpl
+
+#define parcAtomicUint8_Subtract parcAtomicUint8_SubtractImpl
+
+#define parcAtomicUint8_CompareAndSwap parcAtomicUint8_CompareAndSwapImpl
+
+#else
+
+#define parcAtomicUint8_Add(_atomic_uint8_, _addend_) \
+ __sync_add_and_fetch(_atomic_uint8_, _addend_)
+
+#define parcAtomicUint8_Subtract(_atomic_uint8_, _subtrahend_) \
+ __sync_sub_and_fetch(_atomic_uint8_, _subtrahend_)
+
+#define parcAtomicUint8_CompareAndSwap(_atomic_uint8_, _predicate_, _newValue_) \
+ __sync_bool_compare_and_swap(_atomic_uint8_, _predicate_, _newValue_)
+#endif
+
+#define parcAtomicUint8_Increment(_atomic_uint8_) parcAtomicUint8_Add(_atomic_uint8_, 1)
+#define parcAtomicUint8_Decrement(_atomic_uint8_) parcAtomicUint8_Subtract(_atomic_uint8_, 1)
+
+/**
+ * Increase the number of references to a `PARCAtomicUint8` instance.
+ *
+ * Note that new `PARCAtomicUint8` is not created,
+ * only that the given `PARCAtomicUint8` reference count is incremented.
+ * Discard the reference by invoking `parcAtomicUint8_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * PARCAtomicUint8 *b = parcAtomicUint8_Acquire();
+ *
+ * parcAtomicUint8_Release(&a);
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint8 *parcAtomicUint8_Acquire(const PARCAtomicUint8 *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcAtomicUint8_OptionalAssertValid(_instance_)
+#else
+# define parcAtomicUint8_OptionalAssertValid(_instance_) parcAtomicUint8_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCAtomicUint8` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * parcAtomicUint8_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ */
+void parcAtomicUint8_AssertValid(const PARCAtomicUint8 *instance);
+
+/**
+ * Create an instance of PARCAtomicUint8
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCAtomicUint8 instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint8 *parcAtomicUint8_Create(uint8_t);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint8 instance.
+ * @param [in] other A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ * PARCAtomicUint8 *b = parcAtomicUint8_Create();
+ *
+ * if (parcAtomicUint8_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint8_Release(&a);
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcAtomicUint8_Equals
+ */
+int parcAtomicUint8_Compare(const PARCAtomicUint8 *instance, const PARCAtomicUint8 *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCAtomicUint8` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * PARCAtomicUint8 *copy = parcAtomicUint8_Copy(&b);
+ *
+ * parcAtomicUint8_Release(&b);
+ * parcAtomicUint8_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCAtomicUint8 *parcAtomicUint8_Copy(const PARCAtomicUint8 *original);
+
+/**
+ * Determine if two `PARCAtomicUint8` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCAtomicUint8` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcAtomicUint8_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcAtomicUint8_Equals(x, y)` must return true if and only if
+ * `parcAtomicUint8_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcAtomicUint8_Equals(x, y)` returns true and
+ * `parcAtomicUint8_Equals(y, z)` returns true,
+ * then `parcAtomicUint8_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcAtomicUint8_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcAtomicUint8_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCAtomicUint8 instance.
+ * @param [in] y A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ * PARCAtomicUint8 *b = parcAtomicUint8_Create();
+ *
+ * if (parcAtomicUint8_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint8_Release(&a);
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ * @see parcAtomicUint8_HashCode
+ */
+bool parcAtomicUint8_Equals(const PARCAtomicUint8 *x, const PARCAtomicUint8 *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcAtomicUint8_Equals} method,
+ * then calling the {@link parcAtomicUint8_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcAtomicUint8_Equals} function,
+ * then calling the `parcAtomicUint8_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * PARCHashCode hashValue = parcAtomicUint8_HashCode(buffer);
+ * parcAtomicUint8_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcAtomicUint8_HashCode(const PARCAtomicUint8 *instance);
+
+/**
+ * Determine if an instance of `PARCAtomicUint8` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * if (parcAtomicUint8_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcAtomicUint8_IsValid(const PARCAtomicUint8 *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCAtomicUint8` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * parcAtomicUint8_Release(&a);
+ * }
+ * @endcode
+ */
+void parcAtomicUint8_Release(PARCAtomicUint8 **instancePtr);
+
+/**
+ * Get the current value of the given `PARCAtomicUint8` instance.
+ *
+ * @param [in] instance A pointer to a valid `PARCAtomicUint8` instance.
+ *
+ * @return the current value of the given `PARCAtomicUint8` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ *
+ * uint8_t value = parcAtomicUint8_GetValue(instance);
+ *
+ * parcAtomicUint8_Release(&instance);
+ * }
+ * @endcode
+ */
+uint8_t parcAtomicUint8_GetValue(const PARCAtomicUint8 *instance);
+#endif
diff --git a/libparc/parc/concurrent/parc_FutureTask.c b/libparc/parc/concurrent/parc_FutureTask.c
new file mode 100755
index 00000000..0ba2c224
--- /dev/null
+++ b/libparc/parc/concurrent/parc_FutureTask.c
@@ -0,0 +1,304 @@
+/*
+ * 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 <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Execution.h>
+
+#include <parc/concurrent/parc_FutureTask.h>
+
+struct PARCFutureTask {
+ void *(*function)(PARCFutureTask *task, void *parameter);
+ void *parameter;
+ void *result;
+ bool isRunning;
+ bool isDone;
+ bool isCancelled;
+};
+
+static void
+_parcFutureTask_Initialise(PARCFutureTask *futureTask)
+{
+ futureTask->result = NULL;
+ futureTask->isDone = false;
+ futureTask->isCancelled = false;
+ futureTask->isRunning = false;
+}
+
+static bool
+_parcFutureTask_Destructor(PARCFutureTask **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCFutureTask pointer.");
+ PARCFutureTask *task = *instancePtr;
+
+ if (parcObject_IsInstanceOf(task->parameter, &PARCObject_Descriptor)) {
+ parcObject_Release(&task->parameter);
+ }
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcFutureTask, PARCFutureTask);
+
+parcObject_ImplementRelease(parcFutureTask, PARCFutureTask);
+
+parcObject_Override(PARCFutureTask, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcFutureTask_Destructor,
+ .copy = (PARCObjectCopy *) parcFutureTask_Copy,
+ .toString = (PARCObjectToString *) parcFutureTask_ToString,
+ .equals = (PARCObjectEquals *) parcFutureTask_Equals,
+ .compare = (PARCObjectCompare *) parcFutureTask_Compare,
+ .hashCode = (PARCObjectHashCode *) parcFutureTask_HashCode,
+ .display = (PARCObjectDisplay *) parcFutureTask_Display);
+
+void
+parcFutureTask_AssertValid(const PARCFutureTask *task)
+{
+ assertTrue(parcFutureTask_IsValid(task),
+ "PARCFutureTask is not valid.");
+}
+
+PARCFutureTask *
+parcFutureTask_Create(void *(*function)(PARCFutureTask *task, void *parameter), void *parameter)
+{
+ PARCFutureTask *result = parcObject_CreateInstance(PARCFutureTask);
+
+ if (parcObject_IsInstanceOf(parameter, &PARCObject_Descriptor)) {
+ parameter = parcObject_Acquire(parameter);
+ }
+
+ if (result != NULL) {
+ result->function = function;
+ result->parameter = parameter;
+ _parcFutureTask_Initialise(result);
+ }
+
+ return result;
+}
+
+int
+parcFutureTask_Compare(const PARCFutureTask *instance, const PARCFutureTask *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCFutureTask *
+parcFutureTask_Copy(const PARCFutureTask *original)
+{
+ PARCFutureTask *result = parcFutureTask_Create(original->function, original->parameter);
+
+ return result;
+}
+
+void
+parcFutureTask_Display(const PARCFutureTask *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCFutureTask@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcFutureTask_Equals(const PARCFutureTask *x, const PARCFutureTask *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->function == y->function) {
+ if (x->parameter == y->parameter) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcFutureTask_HashCode(const PARCFutureTask *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcFutureTask_IsValid(const PARCFutureTask *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcFutureTask_ToJSON(const PARCFutureTask *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcFutureTask_ToString(const PARCFutureTask *instance)
+{
+ char *result = parcMemory_Format("PARCFutureTask@%p\n", instance);
+
+ return result;
+}
+
+bool
+parcFutureTask_Cancel(PARCFutureTask *task, bool mayInterruptIfRunning)
+{
+ bool result = false;
+
+ if (parcObject_Lock(task)) {
+ if (task->isRunning) {
+ if (mayInterruptIfRunning) {
+ printf("Interrupting a running task is not implemented yet.\n");
+ }
+ result = false;
+ } else {
+ task->isCancelled = true;
+ task->isDone = true;
+ parcObject_Notify(task);
+ result = true;
+ }
+
+ parcObject_Unlock(task);
+ }
+
+ return result;
+}
+
+PARCFutureTaskResult
+parcFutureTask_Get(const PARCFutureTask *futureTask, const PARCTimeout *timeout)
+{
+ PARCFutureTaskResult result;
+
+ result.execution = PARCExecution_Timeout;
+ result.value = 0;
+
+ if (parcTimeout_IsImmediate(timeout)) {
+ if (futureTask->isDone) {
+ result.execution = PARCExecution_OK;
+ result.value = futureTask->result;
+ }
+ } else {
+ result.execution = PARCExecution_Interrupted;
+ result.value = 0;
+
+ parcObject_Lock(futureTask);
+ while (!futureTask->isDone) {
+ if (parcTimeout_IsNever(timeout)) {
+ parcObject_Wait(futureTask);
+ result.execution = PARCExecution_OK;
+ result.value = futureTask->result;
+ break;
+ } else {
+ if (parcObject_WaitFor(futureTask, parcTimeout_InNanoSeconds(timeout))) {
+ result.execution = PARCExecution_OK;
+ result.value = futureTask->result;
+ break;
+ }
+ }
+ }
+ parcObject_Unlock(futureTask);
+ }
+
+ return result;
+}
+
+bool
+parcFutureTask_IsCancelled(const PARCFutureTask *task)
+{
+ return task->isCancelled;
+}
+
+bool
+parcFutureTask_IsDone(const PARCFutureTask *task)
+{
+ return task->isDone;
+}
+
+static void *
+_parcFutureTask_Execute(PARCFutureTask *task)
+{
+ task->isRunning = true;
+ void *result = task->function(task, task->parameter);
+ task->isRunning = false;
+
+ return result;
+}
+
+void *
+parcFutureTask_Run(PARCFutureTask *task)
+{
+ if (parcFutureTask_Lock(task)) {
+ if (!task->isCancelled) {
+ task->result = _parcFutureTask_Execute(task);
+ task->isDone = true;
+ parcFutureTask_Notify(task);
+ }
+ parcFutureTask_Unlock(task);
+ } else {
+ trapCannotObtainLock("Cannot lock PARCFutureTask");
+ }
+ return task->result;
+}
+
+bool
+parcFutureTask_RunAndReset(PARCFutureTask *task)
+{
+ bool result = false;
+
+ if (parcObject_Lock(task)) {
+ if (!task->isCancelled) {
+ _parcFutureTask_Execute(task);
+ parcFutureTask_Reset(task);
+ result = true;
+ }
+ parcFutureTask_Unlock(task);
+ } else {
+ trapCannotObtainLock("Cannot lock PARCFutureTask");
+ }
+
+ return result;
+}
+
+void
+parcFutureTask_Reset(PARCFutureTask *task)
+{
+ _parcFutureTask_Initialise(task);
+}
diff --git a/libparc/parc/concurrent/parc_FutureTask.h b/libparc/parc/concurrent/parc_FutureTask.h
new file mode 100755
index 00000000..9a5776c5
--- /dev/null
+++ b/libparc/parc/concurrent/parc_FutureTask.h
@@ -0,0 +1,657 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_FutureTask.h
+ * @ingroup threading
+ * @brief An encapsulated, asynchronous computation.
+ *
+ * This type associates a function and a pointer to data and provides the functionality
+ * to invoke the function supplying the given pointer to data and returning the result.
+ *
+ * The operations of invoking the function and collecting its return value may be asynchronous from each other
+ * in that an attempting to fetch the return value before the function has been invoked
+ * will cause the calling thread to block until the function has been invoked and run to completion.
+ * This enables the use of PARCFutureTask in a work queue, or thread pool where tasks are run asynchronously
+ * from each other and from an originating thread.
+ *
+ * Each instance of the type may be cancelled,
+ * inhibiting a future invocation of the associated function.
+ *
+ * Typical use is a one time invocation of the associated function, induced by the `parcFutureTask_Get`,
+ * but invoking `parcFutureTask_GetAndReset` invokes the associated function and resets the task to the initial state,
+ * permitting a future call to `parcFutureTask_Get` or `parcFutureTask_GetAndReset` the run the associated function again.
+ *
+ */
+#ifndef PARCLibrary_parc_FutureTask
+#define PARCLibrary_parc_FutureTask
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/concurrent/parc_Timeout.h>
+#include <parc/algol/parc_Execution.h>
+
+struct PARCFutureTask;
+typedef struct PARCFutureTask PARCFutureTask;
+
+typedef struct PARCFutureTaskResult {
+ void *value;
+ PARCExecution *execution;
+} PARCFutureTaskResult;
+
+/**
+ * Increase the number of references to a `PARCFutureTask` instance.
+ *
+ * Note that new `PARCFutureTask` is not created,
+ * only that the given `PARCFutureTask` reference count is incremented.
+ * Discard the reference by invoking `parcFutureTask_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * PARCFutureTask *b = parcFutureTask_Acquire();
+ *
+ * parcFutureTask_Release(&a);
+ * parcFutureTask_Release(&b);
+ * }
+ * @endcode
+ */
+PARCFutureTask *parcFutureTask_Acquire(const PARCFutureTask *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcFutureTask_OptionalAssertValid(_instance_)
+#else
+# define parcFutureTask_OptionalAssertValid(_instance_) parcFutureTask_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCFutureTask` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * parcFutureTask_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcFutureTask_Release(&b);
+ * }
+ * @endcode
+ */
+void parcFutureTask_AssertValid(const PARCFutureTask *instance);
+
+/**
+ * Create an instance of `PARCFutureTask`
+ *
+ * If the parameter is an instance of `PARCObject` a reference to the object will
+ * be created and ultimately released via `parcFutureTask_Release`
+ *
+ * @param [in] function A pointer to a function to call.
+ * @param [in] parameter A pointer that will be passed to the function when invoked.
+ *
+ * @return non-NULL A pointer to a valid `PARCFutureTask` instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create(function, parameter);
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCFutureTask *parcFutureTask_Create(void *(*runnable)(PARCFutureTask *task, void *parameter), void *parameter);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ * @param [in] other A pointer to a valid PARCFutureTask instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ * PARCFutureTask *b = parcFutureTask_Create();
+ *
+ * if (parcFutureTask_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcFutureTask_Release(&a);
+ * parcFutureTask_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcFutureTask_Equals
+ */
+int parcFutureTask_Compare(const PARCFutureTask *instance, const PARCFutureTask *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCFutureTask instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCFutureTask` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * PARCFutureTask *copy = parcFutureTask_Copy(&b);
+ *
+ * parcFutureTask_Release(&b);
+ * parcFutureTask_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCFutureTask *parcFutureTask_Copy(const PARCFutureTask *original);
+
+/**
+ * Print a human readable representation of the given `PARCFutureTask`.
+ *
+ * @param [in] instance A pointer to a valid `PARCFutureTask` instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * parcFutureTask_Display(a, 0);
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+void parcFutureTask_Display(const PARCFutureTask *instance, int indentation);
+
+/**
+ * Determine if two `PARCFutureTask` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCFutureTask` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcFutureTask_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcFutureTask_Equals(x, y)` must return true if and only if
+ * `parcFutureTask_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcFutureTask_Equals(x, y)` returns true and
+ * `parcFutureTask_Equals(y, z)` returns true,
+ * then `parcFutureTask_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcFutureTask_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcFutureTask_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCFutureTask instance.
+ * @param [in] y A pointer to a valid PARCFutureTask instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ * PARCFutureTask *b = parcFutureTask_Create();
+ *
+ * if (parcFutureTask_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcFutureTask_Release(&a);
+ * parcFutureTask_Release(&b);
+ * }
+ * @endcode
+ * @see parcFutureTask_HashCode
+ */
+bool parcFutureTask_Equals(const PARCFutureTask *x, const PARCFutureTask *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcFutureTask_Equals} method,
+ * then calling the {@link parcFutureTask_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcFutureTask_Equals} function,
+ * then calling the `parcFutureTask_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * PARCHashCode hashValue = parcFutureTask_HashCode(buffer);
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcFutureTask_HashCode(const PARCFutureTask *instance);
+
+/**
+ * Determine if an instance of `PARCFutureTask` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * if (parcFutureTask_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcFutureTask_IsValid(const PARCFutureTask *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCFutureTask` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+void parcFutureTask_Release(PARCFutureTask **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * PARCJSON *json = parcFutureTask_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcFutureTask_ToJSON(const PARCFutureTask *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCFutureTask`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * char *string = parcFutureTask_ToString(a);
+ *
+ * parcFutureTask_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcFutureTask_Display
+ */
+char *parcFutureTask_ToString(const PARCFutureTask *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcFutureTask_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCFutureTask instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcFutureTask_Lock(object)) {
+ * parcFutureTask_Notify(object);
+ * parcFutureTask_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcFutureTask, PARCFutureTask);
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcFutureTask_Wait`, `parcFutureTask_WaitFor`, `parcFutureTask_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcFutureTask_Lock(object)) {
+ * parcFutureTask_NotifyAll(object);
+ * parcFutureTask_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotifyAll(parcFutureTask, PARCFutureTask);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcFutureTask_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcFutureTask_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcFutureTask, PARCFutureTask);
+
+/**
+ * Obtain the lock on the given `PARCFutureTask` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCFutureTask` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcFutureTask_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcFutureTask, PARCFutureTask);
+
+/**
+ * Try to obtain the advisory lock on the given PARCFutureTask instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCFutureTask instance.
+ *
+ * @return true The PARCFutureTask is locked.
+ * @return false The PARCFutureTask is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcFutureTask_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcFutureTask, PARCFutureTask);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCFutureTask` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * @return true The `PARCFutureTask` was locked and now is unlocked.
+ * @return false The `PARCFutureTask` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcFutureTask_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcFutureTask, PARCFutureTask);
+
+/**
+ * Determine if the advisory lock on the given `PARCFutureTask` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * @return true The `PARCFutureTask` is locked.
+ * @return false The `PARCFutureTask` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcFutureTask_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcFutureTask, PARCFutureTask);
+
+/**
+ * Attempt to cancel the execution of this task.
+ *
+ * This will return `false` if the task is already done or has already been cancelled.
+ * Otherswise, if this task has not started when `parcFutureTask_Cancel` is called, this task will never run.
+ *
+ * If the task is already running, the boolean `mayInterruptIfRunning` may cause the task to be interrupted,
+ * otherwise this function will have no effect.
+ *
+ * After this function returns, subsequent calls to `parcFutureTask_IsDone` will always return true.
+ * Subsequent calls to `parcFutureTask_isCancelled` will always return true if this function returned true.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * @return true The task was cancelled.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFutureTask_Cancel(PARCFutureTask *task, bool mayInterruptIfRunning);
+
+/**
+ * Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFutureTaskResult parcFutureTask_Get(const PARCFutureTask *futureTask, const PARCTimeout *timeout);
+
+/**
+ * Returns true if this task was cancelled before it completed normally.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFutureTask_IsCancelled(const PARCFutureTask *futureTask);
+
+/**
+ * Returns true if this task completed.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFutureTask_IsDone(const PARCFutureTask *futureTask);
+
+/**
+ * Sets this Future to the result of its computation unless it has been cancelled.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return The result returned by the task function.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *parcFutureTask_Run(PARCFutureTask *futureTask);
+
+/**
+ * Executes the computation without setting its result, and then resets this future to initial state, failing to do so if the computation encounters an exception or is cancelled.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return true The task was executed.
+ * @retval false The task was not executed because it was previously completed, or it was cancelled.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFutureTask_RunAndReset(PARCFutureTask *futureTask);
+
+/**
+ * Reset the given PARCFutureTask to the intial state, a subsequent ecutes the computation without setting its result, and then resets this future to initial state, failing to do so if the computation encounters an exception or is cancelled.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return true The task was successfully run
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcFutureTask_Reset(PARCFutureTask *task);
+#endif
diff --git a/libparc/parc/concurrent/parc_Lock.c b/libparc/parc/concurrent/parc_Lock.c
new file mode 100755
index 00000000..d510b5ed
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Lock.c
@@ -0,0 +1,202 @@
+/*
+ * 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 <pthread.h>
+#include <errno.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/concurrent/parc_Lock.h>
+
+struct PARCLock {
+ pthread_mutex_t lock;
+ pthread_mutexattr_t lockAttributes;
+ pthread_cond_t notification;
+ bool locked;
+
+ bool notified;
+};
+
+static void
+_parcLock_Finalize(PARCLock **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCLock pointer.");
+
+ parcLock_OptionalAssertValid(*instancePtr);
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcLock, PARCLock);
+
+parcObject_ImplementRelease(parcLock, PARCLock);
+
+parcObject_ExtendPARCObject(PARCLock, _parcLock_Finalize, NULL, parcLock_ToString, NULL, NULL, NULL, NULL);
+
+void
+parcLock_AssertValid(const PARCLock *instance)
+{
+ assertTrue(parcLock_IsValid(instance),
+ "PARCLock is not valid.");
+}
+
+PARCLock *
+parcLock_Create(void)
+{
+ PARCLock *result = parcObject_CreateInstance(PARCLock);
+
+ pthread_mutexattr_init(&result->lockAttributes);
+ pthread_mutexattr_settype(&result->lockAttributes, PTHREAD_MUTEX_ERRORCHECK);
+
+ pthread_mutex_init(&result->lock, &result->lockAttributes);
+
+ result->locked = false;
+ pthread_cond_init(&result->notification, NULL);
+ result->notified = false;
+ return result;
+}
+
+void
+parcLock_Display(const PARCLock *lock, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCLock@%p {", lock);
+ parcDisplayIndented_PrintLine(indentation + 1, ".locked=%s", lock->locked ? "true" : "false");
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcLock_IsValid(const PARCLock *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+parcLock_BuildString(const PARCLock *lock, PARCBufferComposer *composer)
+{
+ parcBufferComposer_Format(composer, "lock{.state=%s }", lock->locked ? "true" : "false");
+
+ return composer;
+}
+
+char *
+parcLock_ToString(const PARCLock *lock)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ parcLock_BuildString(lock, composer);
+ result = parcBufferComposer_ToString(composer);
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
+
+bool
+parcLock_Unlock(PARCLock *lock)
+{
+ bool result = false;
+
+ parcLock_OptionalAssertValid(lock);
+
+ if (lock->locked) {
+ result = (pthread_mutex_unlock(&lock->lock) == 0);
+ }
+
+ return result;
+}
+
+bool
+parcLock_Lock(PARCLock *lock)
+{
+ bool result = false;
+
+ parcLock_OptionalAssertValid(lock);
+
+ int error = pthread_mutex_lock(&lock->lock);
+
+ if (error == 0) {
+ lock->locked = true;
+ result = true;
+ errno = 0;
+ } else {
+ errno = error;
+ }
+
+ return result;
+}
+
+bool
+parcLock_TryLock(PARCLock *lock)
+{
+ bool result = false;
+
+ parcLock_OptionalAssertValid(lock);
+
+ result = (pthread_mutex_trylock(&lock->lock) == 0);
+ if (result) {
+ lock->locked = true;
+ }
+
+ return result;
+}
+
+bool
+parcLock_IsLocked(const PARCLock *lock)
+{
+ parcLock_OptionalAssertValid(lock);
+
+ return lock->locked;
+}
+
+void
+parcLock_Wait(PARCLock *lock)
+{
+ parcLock_OptionalAssertValid(lock);
+
+ trapUnexpectedStateIf(lock->locked == false,
+ "You must Lock the object before calling parcLock_Wait");
+
+ lock->notified = false;
+ while (lock->notified == false) {
+ pthread_cond_wait(&lock->notification, &lock->lock);
+ }
+}
+
+void
+parcLock_Notify(PARCLock *lock)
+{
+ parcLock_OptionalAssertValid(lock);
+
+ trapUnexpectedStateIf(lock->locked == false,
+ "You must Lock the object before calling parcLock_Notify");
+
+ lock->notified = true;
+ pthread_cond_signal(&lock->notification);
+}
+
diff --git a/libparc/parc/concurrent/parc_Lock.h b/libparc/parc/concurrent/parc_Lock.h
new file mode 100755
index 00000000..ecba1c19
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Lock.h
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_Lock.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_Lock
+#define PARCLibrary_parc_Lock
+#include <stdbool.h>
+
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_JSON.h>
+
+struct PARCLock;
+typedef struct PARCLock PARCLock;
+
+/**
+ * Increase the number of references to a `PARCLock` instance.
+ *
+ * Note that new `PARCLock` is not created,
+ * only that the given `PARCLock` reference count is incremented.
+ * Discard the reference by invoking `parcLock_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * PARCLock *b = parcLock_Acquire();
+ *
+ * parcLock_Release(&a);
+ * parcLock_Release(&b);
+ * }
+ * @endcode
+ */
+PARCLock *parcLock_Acquire(const PARCLock *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcLock_OptionalAssertValid(_instance_)
+#else
+# define parcLock_OptionalAssertValid(_instance_) parcLock_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCLock` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * parcLock_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcLock_Release(&b);
+ * }
+ * @endcode
+ */
+void parcLock_AssertValid(const PARCLock *instance);
+
+/**
+ * Create an instance of PARCLock
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCLock instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * parcLock_Release(&a);
+ * }
+ * @endcode
+ */
+PARCLock *parcLock_Create(void);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ * @param [in] other A pointer to a valid PARCLock instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ * PARCLock *b = parcLock_Create();
+ *
+ * if (parcLock_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcLock_Release(&a);
+ * parcLock_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcLock_Equals
+ */
+int parcLock_Compare(const PARCLock *instance, const PARCLock *other);
+
+/**
+ * Print a human readable representation of the given `PARCLock`.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * parcLock_Display(a, 0);
+ *
+ * parcLock_Release(&a);
+ * }
+ * @endcode
+ */
+void parcLock_Display(const PARCLock *instance, int indentation);
+
+/**
+ * Determine if an instance of `PARCLock` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * if (parcLock_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcLock_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcLock_IsValid(const PARCLock *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCLock` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * parcLock_Release(&a);
+ * }
+ * @endcode
+ */
+void parcLock_Release(PARCLock **instancePtr);
+
+/**
+ * Append a representation of the specified `PARCLock` instance to the given `PARCBufferComposer`.
+ *
+ * @param [in] name A pointer to a `PARCLock` instance whose representation should be appended to the @p composer.
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance to be modified.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcLock_BuildString(instance, result);
+ *
+ * char *string = parcBufferComposer_ToString(result);
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcLock_BuildString(const PARCLock *name, PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCLock`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * char *string = parcLock_ToString(a);
+ *
+ * parcLock_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcLock_Display
+ */
+char *parcLock_ToString(const PARCLock *instance);
+
+/**
+ * Obtain the lock on the given `PARCLock` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] lock A pointer to a valid `PARCLock` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCLock` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcLock_Lock(lock)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+bool parcLock_Lock(PARCLock *lock);
+
+/**
+ * Try to obtain the advisory lock on the given `PARCObject` instance.
+ *
+ * Once the lock is obtained, the caller must release the lock via `parcObject_Unlock`.
+ *
+ * @param [in] lock A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The `PARCObject` is locked.
+ * @return false The `PARCObject` is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcLock_TryLock(object))
+ * ;
+ * }
+ * @endcode
+ */
+bool parcLock_TryLock(PARCLock *lock);
+
+/**
+ * Try to unlock the advisory lock on the given PARCObject instance.
+ *
+ * @param [in] lock A pointer to a valid PARCObject instance.
+ *
+ * @return true The PARCObject was locked and now is unlocked.
+ * @return false The PARCObject was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcLock_Unlock(object);
+ * }
+ * @endcode
+ */
+bool parcLock_Unlock(PARCLock *lock);
+
+/**
+ * Determine if the advisory lock on the given PARCObject instance is locked.
+ *
+ * @param [in] lock A pointer to a valid PARCObject instance.
+ *
+ * @return true The PARCObject is locked.
+ * @return false The PARCObject is unlocked.
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcLock_IsLocked(const PARCLock *lock);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcObject_Notify() function on the same object.
+ *
+ * The calling thread must own this object's lock.
+ * The calling thread will release ownership of this lock and wait until another thread invokes `parcObject_Notify`
+ * on the same object. The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] lock A pointer to a valid PARCObject instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcObject_Wait(object);
+ * }
+ * @endcode
+ */
+void parcLock_Wait(PARCLock *lock);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcObject_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] lock A pointer to a valid `PARCObject` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcObject_Notify(object);
+ * }
+ * @endcode
+ */
+void parcLock_Notify(PARCLock *lock);
+#endif
diff --git a/libparc/parc/concurrent/parc_Notifier.c b/libparc/parc/concurrent/parc_Notifier.c
new file mode 100755
index 00000000..6cba9147
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Notifier.c
@@ -0,0 +1,149 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/concurrent/parc_Notifier.h>
+#include <parc/algol/parc_Object.h>
+
+#ifdef __GNUC__
+#define ATOMIC_ADD_AND_FETCH(ptr, increment) __sync_add_and_fetch(ptr, increment)
+#define ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue) __sync_bool_compare_and_swap(ptr, oldvalue, newvalue)
+#define ATOMIC_FETCH(ptr) ATOMIC_ADD_AND_FETCH(ptr, 0)
+#define ATOMIC_SET(ptr, oldvalue, newvalue) ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue)
+#else
+#error "Only GNUC supported, we need atomic operations"
+#endif
+
+struct parc_notifier {
+ volatile int paused;
+
+ // If the notifications are paused and there is an event,
+ // we indicate that we skipped a notify
+ volatile int skippedNotify;
+
+#define PARCNotifierWriteFd 1
+#define PARCNotifierReadFd 0
+ int fds[2];
+};
+
+static void
+_parcNotifier_Finalize(PARCNotifier **notifierPtr)
+{
+ PARCNotifier *notifier = *notifierPtr;
+
+ close(notifier->fds[0]);
+ close(notifier->fds[1]);
+}
+
+parcObject_ExtendPARCObject(PARCNotifier, _parcNotifier_Finalize, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static bool
+_parcNotifier_MakeNonblocking(PARCNotifier *notifier)
+{
+ // set the read side to be non-blocking
+ int flags = fcntl(notifier->fds[PARCNotifierReadFd], F_GETFL, 0);
+ if (flags == 0) {
+ if (fcntl(notifier->fds[PARCNotifierReadFd], F_SETFL, flags | O_NONBLOCK) == 0) {
+ return true;
+ }
+ }
+ perror("fcntl error");
+ return false;
+}
+
+PARCNotifier *
+parcNotifier_Create(void)
+{
+ PARCNotifier *notifier = parcObject_CreateInstance(PARCNotifier);
+ if (notifier) {
+ notifier->paused = false;
+ notifier->skippedNotify = false;
+
+ int failure = pipe(notifier->fds);
+ assertFalse(failure, "Error on pipe: %s", strerror(errno));
+
+ if (!_parcNotifier_MakeNonblocking(notifier)) {
+ parcObject_Release((void **) &notifier);
+ }
+ }
+
+ return notifier;
+}
+
+parcObject_ImplementAcquire(parcNotifier, PARCNotifier);
+
+parcObject_ImplementRelease(parcNotifier, PARCNotifier);
+
+
+int
+parcNotifier_Socket(PARCNotifier *notifier)
+{
+ return notifier->fds[PARCNotifierReadFd];
+}
+
+bool
+parcNotifier_Notify(PARCNotifier *notifier)
+{
+ if (ATOMIC_BOOL_CAS(&notifier->paused, 0, 1)) {
+ // old value was "0" so we need to send a notification
+ uint8_t one = 1;
+ ssize_t written;
+ do {
+ written = write(notifier->fds[PARCNotifierWriteFd], &one, 1);
+ assertTrue(written >= 0, "Error writing to socket %d: %s", notifier->fds[PARCNotifierWriteFd], strerror(errno));
+ } while (written == 0);
+
+ return true;
+ } else {
+ // we're paused, so count up the pauses
+ ATOMIC_ADD_AND_FETCH(&notifier->skippedNotify, 1);
+ return false;
+ }
+}
+
+void
+parcNotifier_PauseEvents(PARCNotifier *notifier)
+{
+ // reset the skipped counter so we count from now until the StartEvents call
+ notifier->skippedNotify = 0;
+ ATOMIC_BOOL_CAS(&notifier->paused, 0, 1);
+
+ // now clear out the socket
+ uint8_t buffer[16];
+ while (read(notifier->fds[PARCNotifierReadFd], &buffer, 16) > 0) {
+ ;
+ }
+}
+
+void
+parcNotifier_StartEvents(PARCNotifier *notifier)
+{
+ ATOMIC_BOOL_CAS(&notifier->paused, 1, 0);
+ if (notifier->skippedNotify) {
+ // we missed some notifications, so re-signal ourself
+ parcNotifier_Notify(notifier);
+ }
+}
diff --git a/libparc/parc/concurrent/parc_Notifier.h b/libparc/parc/concurrent/parc_Notifier.h
new file mode 100755
index 00000000..44eda3b5
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Notifier.h
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_Notifier.h
+ * @ingroup threading
+ * @brief Inter-thread/process notification
+ *
+ * A 1-way event notification system. The first call to parcNotifier_SetEvent() will post an
+ * event to the parcNotifier_Socket(). Subsequent calls will not post an event. When the
+ * event consumer is ready to handle the event, it calls parcNotifier_PauseEvents(), then processes
+ * the events, then calls parcNotifier_StartEvents().
+ *
+ * @code
+ * {
+ * // example code on the event consumer's side
+ * struct pollfd pfd;
+ * pfd.fd = parcNotifier_Socket(notifier);
+ * pfd.events = POLLIN;
+ *
+ * while(1) {
+ * if (poll(&fd, 1, -1)) {
+ * parcNotifier_PauseEvents(notifier);
+ *
+ * // process events, such as reading from a RingBuffer
+ * void *data;
+ * while (parcRingBuffer1x1_Get(ring, &data)) {
+ * // handle data
+ * }
+ *
+ * parcNotifier_StartEvents(notifier);
+ * }
+ * }
+ * }
+ * @endcode
+ *
+ * The notification system guarantees that no notifications will be missed. However, there may be
+ * extra notifications. For example, in the above code, if an event is signalled between the
+ * parcNotifier_PauseEvents() and parcRingBuffer1x1_Get() calls, then on parcNotifier_StartEvents()
+ * an extra event will be triggered, even though the ring buffer is empty.
+ *
+ */
+
+#ifndef libparc_parc_Notifier_h
+#define libparc_parc_Notifier_h
+
+#include <stdbool.h>
+
+struct parc_notifier;
+typedef struct parc_notifier PARCNotifier;
+
+/**
+ * Create a new instance of `PARCNotifier`
+ *
+ * @return A new instance of `PARCNotifier`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCNotifier *parcNotifier_Create(void);
+
+/**
+ * Increase the number of references to a `PARCNotifier`.
+ *
+ * Note that new `PARCNotifier` is not created,
+ * only that the given `PARCNotifier` reference count is incremented.
+ * Discard the reference by invoking `parcNotifier_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCNotifier` instance.
+ *
+ * @return The input `PARCNotifier` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCNotifier *a = parcNotifier_Create(...);
+ *
+ * PARCNotifier *b = parcNotifier_Acquire(a);
+ *
+ * parcNotifier_Release(&a);
+ * parcNotifier_Release(&b);
+ * }
+ * @endcode
+ */
+PARCNotifier *parcNotifier_Acquire(const PARCNotifier *notifier);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release, which will be set to NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCNotifier *a = parcNotifier_Create(...);
+ *
+ * parcNotifier_Release(&a);
+ * }
+ * @endcode
+ */
+void parcNotifier_Release(PARCNotifier **notifier);
+
+/**
+ * Fetches the notification socket
+ *
+ * The notification socket may be used in select() or poll() or similar
+ * functions. You should not read or write to the socket.
+ *
+ * @param [in] notifier The instance of `PARCNotifier`
+ *
+ * @return The notification socket.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int parcNotifier_Socket(PARCNotifier *notifier);
+
+/**
+ * Sends a notification to the notifier socket
+ *
+ * @param [in] notifier The instance of `PARCNotifier`
+ *
+ * @return True is successsful, else false.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcNotifier_Notify(PARCNotifier *notifier);
+
+/**
+ * Pause the event stream of the Notifier
+ *
+ * @param [in] notifier The instance of `PARCNotifier`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcNotifier_PauseEvents(PARCNotifier *notifier);
+
+/**
+ * Restart the event stream of the Notifier
+ *
+ * @param [in] notifier The instance of `PARCNotifier`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcNotifier_StartEvents(PARCNotifier *notifier);
+#endif // libparc_parc_Notifier_h
diff --git a/libparc/parc/concurrent/parc_RingBuffer.c b/libparc/parc/concurrent/parc_RingBuffer.c
new file mode 100755
index 00000000..9492ae92
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer.c
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/**
+ * This is a facade over the 1x1 or NxM ring buffers.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <LongBow/runtime.h>
+
+#include <parc/concurrent/parc_RingBuffer.h>
+
+struct parc_ringbuffer {
+ PARCRingBufferInterface *interface;
+};
+
+static void
+_parcRingBuffer_Finalize(PARCRingBuffer **pointer)
+{
+ PARCRingBuffer *buffer = *pointer;
+ buffer->interface->release(&(buffer->interface));
+}
+
+parcObject_ExtendPARCObject(PARCRingBuffer, _parcRingBuffer_Finalize, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCRingBuffer *
+parcRingBuffer_Create(PARCRingBufferInterface *interface)
+{
+ PARCRingBuffer *ring = parcObject_CreateInstance(PARCRingBuffer);
+ ring->interface = interface;
+ return ring;
+}
+
+parcObject_ImplementAcquire(parcRingBuffer, PARCRingBuffer);
+
+parcObject_ImplementRelease(parcRingBuffer, PARCRingBuffer);
+
+bool
+parcRingBuffer_Put(PARCRingBuffer *ring, void *data)
+{
+ return ring->interface->put(ring->interface->instance, data);
+}
+
+bool
+parcRingBuffer_Get(PARCRingBuffer *ring, void **outputDataPtr)
+{
+ return ring->interface->put(ring->interface->instance, outputDataPtr);
+}
+
+uint32_t
+parcRingBuffer_Remaining(PARCRingBuffer *ring)
+{
+ return ring->interface->remaining(ring->interface->instance);
+}
diff --git a/libparc/parc/concurrent/parc_RingBuffer.h b/libparc/parc/concurrent/parc_RingBuffer.h
new file mode 100755
index 00000000..211f044e
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_RingBuffer.h
+ * @ingroup threading
+ * @brief A thread-safe ring buffer.
+ *
+ * A fixed size, thread safe ring buffer. It can have multiple producers and multiple
+ * consumers. All exclusion is done inside the ring buffer.
+ *
+ * This is a non-blocking data structure.
+ *
+ * If the user knows there is only one producer and one consumer, you can create the ring buffer with
+ * `parcRingBuffer_CreateSingleProducerSingleConsumer`. Such a ring buffer can have at most 2 references.
+ *
+ */
+
+#ifndef libparc_parc_RingBuffer_h
+#define libparc_parc_RingBuffer_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct parc_ringbuffer;
+typedef struct parc_ringbuffer PARCRingBuffer;
+
+/**< Will be called for each data item on destroy */
+typedef void (RingBufferEntryDestroyer)(void **entryPtr);
+
+struct parc_ringbuffer_impl;
+typedef struct parc_ringbuffer_interface PARCRingBufferInterface;
+
+struct parc_ringbuffer_interface {
+ void *instance;
+ void * (*acquire)(PARCRingBufferInterface *ring);
+ void (*release)(PARCRingBufferInterface **ring);
+ bool (*put)(PARCRingBufferInterface *ring, void *data);
+ bool (*get)(PARCRingBufferInterface *ring, void *outputDataPtr);
+ bool (*remaining)(PARCRingBufferInterface *ring);
+};
+
+/**
+ * Creates a ring buffer of the given size, which must be a power of 2.
+ *
+ * The ring buffer can store up to (elements-1) items in the buffer. The buffer can
+ * be shared between multiple producers and consumers. Each of them should be
+ * given out from a call to {@link parcRingBuffer_Acquire} to create reference counted
+ * copies.
+ *
+ * The reference count is "1" on return.
+ *
+ * @param [in] interface A pointer to the underlying instance and the interface functions for acquire,
+ * release,put,get,and remaining.
+ *
+ * @return non-null An pointer to a new allocated `PARCRingBuffer`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBuffer *parcRingBuffer_Create(PARCRingBufferInterface *interface);
+
+/**
+ * Acquire a new reference to an instance of `PARCRingBuffer`.
+ *
+ * A RING WITHOUT LOCKS CAN ONLY HAVE 2 REFERENCES.
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] ring The instance of `PARCRingBuffer` to which to refer.
+ *
+ * @return The same value as the input parameter @p ring
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+
+PARCRingBuffer *parcRingBuffer_Acquire(const PARCRingBuffer *ring);
+
+/**
+ * Releases a reference. The buffer will be destroyed after the last release.
+ *
+ * If the destroyer was specified on create, it will be called on each entry in the buffer
+ * when the buffer is destroyed.
+ *
+ * @param [in,out] ringPtr The pointer to the pointer of the `PARCRingBuffer` to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcRingBuffer_Release(PARCRingBuffer **ringPtr);
+
+/**
+ * Non-blocking attempt to put item on ring. May return false if ring is full.
+ *
+ * @param [in,out] ring The instance of `PARCRingBuffer` to modify'
+ * @param [in] data A pointer to teh data to put on the ring.
+ *
+ * @return true Data was put on the queue
+ * @return false Would have blocked, the queue was full
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBuffer_Put(PARCRingBuffer *ring, void *data);
+
+/**
+ * Gets the next item off the ring, or returns false if would have blocked.
+ *
+ * Non-blocking, gets an item off the ring, or returns false if would block
+ *
+ * @param [in] ring The pointer to the `PARCRingBuffer`
+ * @param [out] outputDataPtr The output pointer
+ *
+ * @return true Data returned in the output argument
+ * @return false Ring is empty, no data returned.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBuffer_Get(PARCRingBuffer *ring, void **outputDataPtr);
+
+/**
+ * Returns the remaining capacity of the ring
+ *
+ * Returns the remaining capacity of the ring. This does not guarantee the next
+ * Put will not block, as other producers might consumer the space between calls.
+ *
+ * @param [in] ring The pointer to the `PARCRingBuffer`
+ *
+ * @return The uint32_t remaining capacity of the ring.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint32_t parcRingBuffer_Remaining(PARCRingBuffer *ring);
+#endif // libparc_parc_RingBuffer_h
diff --git a/libparc/parc/concurrent/parc_RingBuffer_1x1.c b/libparc/parc/concurrent/parc_RingBuffer_1x1.c
new file mode 100755
index 00000000..a023f4d7
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer_1x1.c
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+/**
+ * A thread-safe fixed size ring buffer.
+ *
+ * A single-producer/single-consumer version is lock-free, along the lines of Lamport, "Proving the
+ * Correctness of Multiprocess Programs," IEEE Trans on Software Engineering 3(2), Mar 1977, which
+ * is based on reading/writing native types upto the data bus width being atomic operations.
+ *
+ * It can hold (elements-1) data items. elements must be a power of 2.
+ *
+ * The writer_head is where the next element should be inserted. The reader_tail is where the next element
+ * should be read.
+ *
+ * All index variables are unbounded uint32_t. This means they just keep counting up. To get the actual
+ * index in the ring, we mask with (elements-1). For example, a ring with 16 elements will be masked with
+ * 0x0000000F. We call this the "ring_mask".
+ *
+ * Because we never let the writer_head and reader_tail differ by more than (elements-1), this technique of
+ * masking works just the same as taking the modulus. There's no problems at the uint32_t wraparound either.
+ * The only math operation we are doing is "+1" which works just fine to wrap a uint32_t.
+ *
+ * Let's look at some exampls. I'm going to use a uint16_t so its easier to write the numbers. Let's assume
+ * that the ring size is 16, so the first ring is (0 - 15).
+ * head tail
+ * initialize 0 0
+ * put x 3 3 0
+ * get x 2 3 2
+ * put x 13 16 2
+ * put x 1 17 2
+ * put x 1 blocks # (0x11 + 1) & 0x0F == tail & 0x0F
+ * get x 14 17 16
+ * get x 1 17 17 # ring is now empty
+ * ...
+ * empty 65534 65534 # 0xFFFE 0xFFFE masked = 14 14
+ * put x1 65535 65534 # 0xFFFF 0xFFFE masked = 15 14
+ * put x1 0 65534 # 0x0000 0xFFFE masked = 0 14
+ * ...
+ *
+ * The number of remaining available items is (ring_mask + reader_tail - writer_head) & ring_mask.
+ * head tail remaining
+ * initialize 0 0 15 + 0 - 0 = 15
+ * put x 3 3 0 15 + 0 - 3 = 12
+ * get x 2 3 2
+ * put x 13 16 2 15 + 2 - 16 = 1
+ * put x 1 17 2 15 + 2 - 17 = 0
+ * put x 1 blocks
+ * get x 14 17 16 15 + 16 - 17 = 14
+ * get x 1 17 17 15 + 17 - 17 = 15
+ * ...
+ * empty 65534 65534 15 + 65534 - 65534 = 13 - 65534 = 13 - (-2) = 15
+ * put x1 65535 65534 15 + 65534 - 65535 = 13 - 65535 = 13 - (-1) = 14
+ * put x1 0 65534 15 + 65534 - 0 = 13 - 65535 = 13 - ( 0) = 13
+ * ...
+ *
+ * If (writer_head + 1) & ring_mask == reader_tail, then the ring is full.
+ * If writer_head == reader_tail, then the ring is empty.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <LongBow/runtime.h>
+
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+
+#ifdef __GNUC__
+
+// on x86 or x86_64, simple assignment will work
+#if (__x86_64__ || __i386__)
+#define ATOMIC_ADD_AND_FETCH(ptr, increment) __sync_add_and_fetch(ptr, increment)
+#define ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue) __sync_bool_compare_and_swap(ptr, oldvalue, newvalue)
+#define ATOMIC_FETCH(ptr) *(ptr)
+#define ATOMIC_SET(ptr, oldvalue, newvalue) *(ptr) = newvalue
+#else
+#define ATOMIC_ADD_AND_FETCH(ptr, increment) __sync_add_and_fetch(ptr, increment)
+#define ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue) __sync_bool_compare_and_swap(ptr, oldvalue, newvalue)
+#define ATOMIC_FETCH(ptr) ATOMIC_ADD_AND_FETCH(ptr, 0)
+#define ATOMIC_SET(ptr, oldvalue, newvalue) ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue)
+#endif
+
+#else
+#error "Only GNUC supported, we need atomic operations"
+#endif
+
+struct parc_ringbuffer_1x1 {
+ // LP64 LP32
+ volatile uint32_t writer_head; // 0- 3 0
+ volatile uint32_t reader_tail; // 4- 7 4
+ uint32_t elements; // 8-11 8
+ uint32_t ring_mask; // 12-15 12
+
+ RingBufferEntryDestroyer *destroyer; // 16-23 16
+ void **buffer; // 24-31 24
+};
+
+static bool
+_isPowerOfTwo(uint32_t x)
+{
+ return ((x != 0) && !(x & (x - 1)));
+}
+
+static void
+_destroy(PARCRingBuffer1x1 **ringptr)
+{
+ PARCRingBuffer1x1 *ring = *ringptr;
+
+ if (ring->destroyer) {
+ void *ptr = NULL;
+ while (parcRingBuffer1x1_Get(ring, &ptr)) {
+ ring->destroyer(&ptr);
+ }
+ }
+ parcMemory_Deallocate((void **) &(ring->buffer));
+}
+
+parcObject_ExtendPARCObject(PARCRingBuffer1x1, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCRingBuffer1x1 *
+_create(uint32_t elements, RingBufferEntryDestroyer *destroyer)
+{
+ PARCRingBuffer1x1 *ring = parcObject_CreateInstance(PARCRingBuffer1x1);
+ assertNotNull(ring, "parcObject_Create returned NULL");
+
+ ring->buffer = parcMemory_AllocateAndClear(sizeof(void *) * elements);
+ assertNotNull((ring->buffer), "parcMemory_AllocateAndClear() failed to allocate array of %u pointers", elements);
+
+ ring->writer_head = 0;
+ ring->reader_tail = 0;
+ ring->elements = elements;
+ ring->destroyer = destroyer;
+ ring->ring_mask = elements - 1;
+
+ return ring;
+}
+
+PARCRingBuffer1x1 *
+parcRingBuffer1x1_Create(uint32_t elements, RingBufferEntryDestroyer *destroyer)
+{
+ assertTrue(_isPowerOfTwo(elements), "Parameter elements must be a power of 2, got %u", elements);
+ return _create(elements, destroyer);
+}
+
+
+parcObject_ImplementAcquire(parcRingBuffer1x1, PARCRingBuffer1x1);
+
+parcObject_ImplementRelease(parcRingBuffer1x1, PARCRingBuffer1x1);
+
+/**
+ * Put is protected by the writer mutex. This means that the tail mutex could
+ * actually increase while this is happening. That's ok. Increasing the tail
+ * just means there is _more_ room in the ring. We only modify writer_head.
+ */
+bool
+parcRingBuffer1x1_Put(PARCRingBuffer1x1 *ring, void *data)
+{
+ // Our speculative operation
+ // The consumer modifies reader_tail, so make sure that's an atomic read.
+ // only the prodcuer modifies writer_head, so there's only us
+
+ uint32_t writer_head = ring->writer_head;
+ uint32_t reader_tail = ATOMIC_FETCH(&ring->reader_tail);
+
+ uint32_t writer_next = (writer_head + 1) & ring->ring_mask;
+
+ // ring is full
+ if (writer_next == reader_tail) {
+ return false;
+ }
+
+ assertNull(ring->buffer[writer_head], "Ring index %u is not null!", writer_head);
+ ring->buffer[writer_head] = data;
+
+ // we're using this just for atomic write to the integer
+ ATOMIC_SET(&ring->writer_head, writer_head, writer_next);
+
+ return true;
+}
+
+bool
+parcRingBuffer1x1_Get(PARCRingBuffer1x1 *ring, void **outputDataPtr)
+{
+ // do our speculative operation.
+ // The producer modifies writer_head, so make sure that's an atomic read.
+ // only the consumer modifies reader_tail, so there's only us
+
+ uint32_t writer_head = ATOMIC_FETCH(&ring->writer_head); // native type assignment is atomic
+ uint32_t reader_tail = ring->reader_tail;
+ uint32_t reader_next = (reader_tail + 1) & ring->ring_mask;
+
+ // ring is empty
+ if (writer_head == reader_tail) {
+ return false;
+ }
+
+ // now try to commit it
+ ATOMIC_SET(&ring->reader_tail, reader_tail, reader_next);
+
+ *outputDataPtr = ring->buffer[reader_tail];
+
+ // for sanity's sake
+ ring->buffer[reader_tail] = NULL;
+
+ return true;
+}
+
+uint32_t
+parcRingBuffer1x1_Remaining(PARCRingBuffer1x1 *ring)
+{
+ uint32_t writer_head = ATOMIC_FETCH(&ring->writer_head);
+ uint32_t reader_tail = ATOMIC_FETCH(&ring->reader_tail);
+
+ return (ring->ring_mask + reader_tail - writer_head) & ring->ring_mask;
+}
diff --git a/libparc/parc/concurrent/parc_RingBuffer_1x1.h b/libparc/parc/concurrent/parc_RingBuffer_1x1.h
new file mode 100755
index 00000000..4fd48e6b
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer_1x1.h
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_RingBuffer_1x1.h
+ * @ingroup threading
+ * @brief A single producer, single consumer ring buffer
+ *
+ * This is useful for synchronizing two (and exactly two) threads in one direction. The
+ * implementation will use a lock-free algorithm.
+ *
+ * Complies with the PARCRingBuffer generic facade.
+ *
+ */
+
+#ifndef libparc_parc_RingBuffer_1x1_h
+#define libparc_parc_RingBuffer_1x1_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct parc_ringbuffer_1x1;
+typedef struct parc_ringbuffer_1x1 PARCRingBuffer1x1;
+
+/**< Will be called for each data item on destroy */
+typedef void (RingBufferEntryDestroyer)(void **entryPtr);
+
+/**
+ * Creates a ring buffer of the given size, which must be a power of 2.
+ *
+ * The ring buffer can store up to (elements-1) items in the buffer. The buffer can
+ * be shared between multiple producers and consumers. Each of them should be
+ * given out from a call to {@link parcRingBuffer_Acquire} to create reference counted
+ * copies.
+ *
+ * The reference count is "1" on return.
+ *
+ * @param [in] elements A power of 2, indicating the maximum size of the buffer.
+ * @param [in] destroyer Will be called for each ring entry when when the ring is destroyed. May be null.
+ *
+ * @return non-null An allocated ring buffer.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBuffer1x1 *parcRingBuffer1x1_Create(uint32_t elements, RingBufferEntryDestroyer *destroyer);
+
+/**
+ * A reference counted copy of the buffer.
+ *
+ * A RING WITHOUT LOCKS CAN ONLY HAVE 2 REFERENCES.
+ *
+ * @param [in] ring The instance of `PARCRingBuffer1x1` to acquire.
+ *
+ * @return non-null A reference counted copy of the ring buffer.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBuffer1x1 *parcRingBuffer1x1_Acquire(const PARCRingBuffer1x1 *ring);
+
+/**
+ * Releases a reference. The buffer will be destroyed after the last release.
+ *
+ * If the destroyer was specified on create, it will be called on each entry in the buffer
+ * when the buffer is destroyed.
+ *
+ * @param [in,out] ringPtr The pointer to the pointer of the `PARCRingBuffer1x1` to be released.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcRingBuffer1x1_Release(PARCRingBuffer1x1 **ringPtr);
+
+/**
+ * Non-blocking attempt to put item on ring. May return `false` if ring is full.
+ *
+ * @param [in,out] ring The instance of `PARCRingBuffer1x1` on which to put the @p data.
+ * @param [in] data The data to put on the @p ring.
+ *
+ * @return `true` Data was put on the queue
+ * @return `false` Would have blocked, the queue was full
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBuffer1x1_Put(PARCRingBuffer1x1 *ring, void *data);
+
+/**
+ * Gets the next item off the ring, or returns false if would have blocked.
+ *
+ * Non-blocking, gets an item off the ring, or returns false if would block
+ *
+ * @param [in] ring The ring buffer
+ * @param [out] outputDataPtr The output pointer
+ *
+ * @return true Data returned in the output argument
+ * @return false Ring is empty, no data returned.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBuffer1x1_Get(PARCRingBuffer1x1 *ring, void **outputDataPtr);
+
+/**
+ * Returns the remaining capacity of the ring
+ *
+ * Returns the remaining capacity of the ring. This does not guarantee the next
+ * Put will not block, as other producers might consumer the space between calls.
+ *
+ * @param [in] ring The instance of `PARCRingBuffer1x1` .
+ *
+ * @return The remaining capacity on the ring.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint32_t parcRingBuffer1x1_Remaining(PARCRingBuffer1x1 *ring);
+#endif // libparc_parc_RingBuffer_1x1_h
diff --git a/libparc/parc/concurrent/parc_RingBuffer_NxM.c b/libparc/parc/concurrent/parc_RingBuffer_NxM.c
new file mode 100755
index 00000000..15ec849b
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer_NxM.c
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+/**
+ * A thread-safe fixed size ring buffer.
+ *
+ * The multiple producer, multiple consumer version uses a pthread mutex around a NxM ring buffer.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <LongBow/runtime.h>
+
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+#include <parc/concurrent/parc_RingBuffer_NxM.h>
+
+struct parc_ringbuffer_NxM {
+ PARCRingBuffer1x1 *onebyone;
+
+ // This protectes the overall data structure for Acquire and Release
+ pthread_mutex_t allocation_mutex;
+
+ pthread_mutex_t writer_mutex;
+ pthread_mutex_t reader_mutex;
+
+ RingBufferEntryDestroyer *destroyer;
+};
+
+/*
+ * Attemps a lock and returns false if we cannot get it.
+ *
+ * @endcode
+ */
+static bool
+_lock(pthread_mutex_t *mutex)
+{
+ int failure = pthread_mutex_lock(mutex);
+ assertFalse(failure, "Error locking mutex: (%d) %s\n", errno, strerror(errno));
+ return true;
+}
+
+static bool
+_unlock(pthread_mutex_t *mutex)
+{
+ int failure = pthread_mutex_unlock(mutex);
+ assertFalse(failure, "Error unlocking mutex: (%d) %s\n", errno, strerror(errno));
+ return true;
+}
+
+static void
+_destroy(PARCRingBufferNxM **ringptr)
+{
+ PARCRingBufferNxM *ring = *ringptr;
+
+ if (ring->destroyer) {
+ void *ptr = NULL;
+ while (parcRingBufferNxM_Get(ring, &ptr)) {
+ ring->destroyer(&ptr);
+ }
+ }
+ parcRingBuffer1x1_Release(&ring->onebyone);
+}
+
+
+parcObject_ExtendPARCObject(PARCRingBufferNxM, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCRingBufferNxM *
+_create(uint32_t elements, RingBufferEntryDestroyer *destroyer)
+{
+ PARCRingBufferNxM *ring = parcObject_CreateInstance(PARCRingBufferNxM);
+ assertNotNull(ring, "parcObject_Create returned NULL");
+
+ ring->onebyone = parcRingBuffer1x1_Create(elements, destroyer);
+ ring->destroyer = destroyer;
+ pthread_mutex_init(&ring->allocation_mutex, NULL);
+ pthread_mutex_init(&ring->writer_mutex, NULL);
+ pthread_mutex_init(&ring->reader_mutex, NULL);
+ return ring;
+}
+
+PARCRingBufferNxM *
+parcRingBufferNxM_Create(uint32_t elements, RingBufferEntryDestroyer *destroyer)
+{
+ return _create(elements, destroyer);
+}
+
+PARCRingBufferNxM *
+parcRingBufferNxM_Acquire(PARCRingBufferNxM *ring)
+{
+ PARCRingBufferNxM *acquired;
+
+ _lock(&ring->allocation_mutex);
+ acquired = parcObject_Acquire(ring);
+ _unlock(&ring->allocation_mutex);
+
+ return acquired;
+}
+
+void
+parcRingBufferNxM_Release(PARCRingBufferNxM **ringPtr)
+{
+ PARCRingBufferNxM *ring = *ringPtr;
+ _lock(&ring->allocation_mutex);
+ parcObject_Release((void **) ringPtr);
+ _unlock(&ring->allocation_mutex);
+}
+
+/**
+ * Put is protected by the writer mutex. This means that the tail mutex could
+ * actually increase while this is happening. That's ok. Increasing the tail
+ * just means there is _more_ room in the ring. We only modify writer_head.
+ */
+bool
+parcRingBufferNxM_Put(PARCRingBufferNxM *ring, void *data)
+{
+ // **** LOCK
+ _lock(&ring->writer_mutex);
+ bool success = parcRingBuffer1x1_Put(ring->onebyone, data);
+ // **** UNLOCK
+ _unlock(&ring->writer_mutex);
+ return success;
+}
+
+bool
+parcRingBufferNxM_Get(PARCRingBufferNxM *ring, void **outputDataPtr)
+{
+ // **** LOCK
+ _lock(&ring->reader_mutex);
+ bool success = parcRingBuffer1x1_Get(ring->onebyone, outputDataPtr);
+ // **** UNLOCK
+ _unlock(&ring->reader_mutex);
+ return success;
+}
+
+uint32_t
+parcRingBufferNxM_Remaining(PARCRingBufferNxM *ring)
+{
+ _lock(&ring->writer_mutex);
+ _lock(&ring->reader_mutex);
+
+ uint32_t remaining = parcRingBuffer1x1_Remaining(ring->onebyone);
+
+ _unlock(&ring->reader_mutex);
+ _unlock(&ring->writer_mutex);
+
+ return remaining;
+}
diff --git a/libparc/parc/concurrent/parc_RingBuffer_NxM.h b/libparc/parc/concurrent/parc_RingBuffer_NxM.h
new file mode 100755
index 00000000..8cf38fdc
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer_NxM.h
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_RingBuffer_NxM.h
+ * @ingroup threading
+ * @brief A multiple producer, multiple consumer ring buffer
+ *
+ * This is useful for synchronizing one or more producers with one or more consumers.
+ * The implementation may use locks.
+ *
+ * Complies with the PARCRingBuffer generic facade.
+ *
+ */
+
+#ifndef libparc_parc_RingBuffer_NxM_h
+#define libparc_parc_RingBuffer_NxM_h
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+
+struct parc_ringbuffer_NxM;
+/**
+ * @typedef PARCRingBufferNxM
+ */
+typedef struct parc_ringbuffer_NxM PARCRingBufferNxM;
+
+/**
+ * Creates a ring buffer of the given size, which must be a power of 2.
+ *
+ * The ring buffer can store up to (elements-1) items in the buffer. The buffer can
+ * be shared between multiple producers and consumers. Each of them should be
+ * given out from a call to {@link parcRingBuffer_Acquire} to create reference counted
+ * copies.
+ *
+ * The reference count is "1" on return.
+ *
+ * @param [in] elements A power of 2, indicating the maximum size of the buffer.
+ * @param [in] destroyer Will be called for each ring entry when when the ring is destroyed. May be null.
+ *
+ * @return non-null An allocated ring buffer.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBufferNxM *parcRingBufferNxM_Create(uint32_t elements, RingBufferEntryDestroyer *destroyer);
+
+/**
+ * A reference counted copy of the buffer.
+ *
+ * A RING WITHOUT LOCKS CAN ONLY HAVE 2 REFERENCES.
+ *
+ * @param [in] ring A pointer to the `PARCRingBufferNxM` to be acquired.
+ *
+ * @return non-null A reference counted copy of the ring buffer
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBufferNxM *parcRingBufferNxM_Acquire(PARCRingBufferNxM *ring);
+
+/**
+ * Releases a reference. The buffer will be destroyed after the last release.
+ *
+ * If the destroyer was specified on create, it will be called on each entry in the buffer
+ * when the buffer is destroyed.
+ *
+ * @param [in,out] ringPtr A pointer to the pointer to the `PARCRingBufferNxM` to be released.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcRingBufferNxM_Release(PARCRingBufferNxM **ringPtr);
+
+/**
+ * Non-blocking attempt to put item on ring. May return false if ring is full.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in,out] ring A pointer to the `PARCRingBufferNxM` on which to put @p data.
+ * @param [in] data A pointer to data to put on @p ring.
+ *
+ * @return `true` Data was put on the queue
+ * @return `false` Would have blocked, the queue was full
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBufferNxM_Put(PARCRingBufferNxM *ring, void *data);
+
+/**
+ * Gets the next item off the ring, or returns false if would have blocked.
+ *
+ * Non-blocking, gets an item off the ring, or returns false if would block
+ *
+ * @param [in] ring The ring buffer
+ * @param [out] outputDataPtr The output pointer
+ *
+ * @return `true` Data returned in the output argument
+ * @return `false` Ring is empty, no data returned.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBufferNxM_Get(PARCRingBufferNxM *ring, void **outputDataPtr);
+
+/**
+ * Returns the remaining capacity of the ring
+ *
+ * Returns the remaining capacity of the ring. This does not guarantee the next
+ * Put will not block, as other producers might consumer the space between calls.
+ *
+ * @param [in] ring The ring buffer
+ *
+ * @return the remaining capacity of @p ring.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint32_t parcRingBufferNxM_Remaining(PARCRingBufferNxM *ring);
+#endif // libparc_parc_RingBuffer_NxM_h
diff --git a/libparc/parc/concurrent/parc_ScheduledTask.c b/libparc/parc/concurrent/parc_ScheduledTask.c
new file mode 100755
index 00000000..14c1d556
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ScheduledTask.c
@@ -0,0 +1,203 @@
+/*
+ * 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 <sys/time.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+
+#include <parc/concurrent/parc_ScheduledTask.h>
+#include <parc/concurrent/parc_FutureTask.h>
+
+struct PARCScheduledTask {
+ PARCFutureTask *task;
+ uint64_t executionTime;
+};
+
+static bool
+_parcScheduledTask_Destructor(PARCScheduledTask **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCScheduledTask pointer.");
+ PARCScheduledTask *task = *instancePtr;
+
+ parcFutureTask_Release(&task->task);
+ return true;
+}
+
+parcObject_ImplementAcquire(parcScheduledTask, PARCScheduledTask);
+
+parcObject_ImplementRelease(parcScheduledTask, PARCScheduledTask);
+
+parcObject_Override(PARCScheduledTask, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcScheduledTask_Destructor,
+ .copy = (PARCObjectCopy *) parcScheduledTask_Copy,
+ .toString = (PARCObjectToString *) parcScheduledTask_ToString,
+ .equals = (PARCObjectEquals *) parcScheduledTask_Equals,
+ .compare = (PARCObjectCompare *) parcScheduledTask_Compare,
+ .hashCode = (PARCObjectHashCode *) parcScheduledTask_HashCode,
+ .display = (PARCObjectDisplay *) parcScheduledTask_Display);
+
+void
+parcScheduledTask_AssertValid(const PARCScheduledTask *instance)
+{
+ assertTrue(parcScheduledTask_IsValid(instance),
+ "PARCScheduledTask is not valid.");
+}
+
+
+PARCScheduledTask *
+parcScheduledTask_Create(PARCFutureTask *task, uint64_t executionTime)
+{
+ PARCScheduledTask *result = parcObject_CreateInstance(PARCScheduledTask);
+
+ if (result != NULL) {
+ result->task = parcFutureTask_Acquire(task);
+ result->executionTime = executionTime;
+ }
+
+ return result;
+}
+
+int
+parcScheduledTask_Compare(const PARCScheduledTask *instance, const PARCScheduledTask *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCScheduledTask *
+parcScheduledTask_Copy(const PARCScheduledTask *original)
+{
+ PARCScheduledTask *result = parcScheduledTask_Create(original->task, original->executionTime);
+
+ return result;
+}
+
+void
+parcScheduledTask_Display(const PARCScheduledTask *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCScheduledTask@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcScheduledTask_Equals(const PARCScheduledTask *x, const PARCScheduledTask *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (parcFutureTask_Equals(x->task, y->task)) {
+ if (x->executionTime == y->executionTime) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcScheduledTask_HashCode(const PARCScheduledTask *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcScheduledTask_IsValid(const PARCScheduledTask *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcScheduledTask_ToJSON(const PARCScheduledTask *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcScheduledTask_ToString(const PARCScheduledTask *instance)
+{
+ char *result = parcMemory_Format("PARCScheduledTask@%p\n", instance);
+
+ return result;
+}
+
+uint64_t
+parcScheduledTask_GetExecutionTime(const PARCScheduledTask *task)
+{
+ return task->executionTime;
+}
+
+bool
+parcScheduledTask_Cancel(PARCScheduledTask *task, bool mayInterruptIfRunning)
+{
+ return parcFutureTask_Cancel(task->task, mayInterruptIfRunning);
+}
+
+PARCFutureTaskResult
+parcScheduledTask_Get(const PARCScheduledTask *task, const PARCTimeout *timeout)
+{
+ return parcFutureTask_Get(task->task, timeout);
+}
+
+PARCFutureTask *
+parcScheduledTask_GetTask(const PARCScheduledTask *task)
+{
+ return task->task;
+}
+
+void *
+parcScheduledTask_Run(const PARCScheduledTask *task)
+{
+ return parcFutureTask_Run(task->task);
+}
+
+bool
+parcScheduledTask_IsCancelled(const PARCScheduledTask *task)
+{
+ return parcFutureTask_IsCancelled(task->task);
+}
+
+bool
+parcScheduledTask_IsDone(const PARCScheduledTask *task)
+{
+ return parcFutureTask_IsDone(task->task);
+}
diff --git a/libparc/parc/concurrent/parc_ScheduledTask.h b/libparc/parc/concurrent/parc_ScheduledTask.h
new file mode 100755
index 00000000..e56fb5f5
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ScheduledTask.h
@@ -0,0 +1,467 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * @file parc_ScheduledTask.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_ScheduledTask
+#define PARCLibrary_parc_ScheduledTask
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/concurrent/parc_FutureTask.h>
+#include <parc/concurrent/parc_Timeout.h>
+
+struct PARCScheduledTask;
+typedef struct PARCScheduledTask PARCScheduledTask;
+
+/**
+ * Increase the number of references to a `PARCScheduledTask` instance.
+ *
+ * Note that new `PARCScheduledTask` is not created,
+ * only that the given `PARCScheduledTask` reference count is incremented.
+ * Discard the reference by invoking `parcScheduledTask_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * PARCScheduledTask *b = parcScheduledTask_Acquire();
+ *
+ * parcScheduledTask_Release(&a);
+ * parcScheduledTask_Release(&b);
+ * }
+ * @endcode
+ */
+PARCScheduledTask *parcScheduledTask_Acquire(const PARCScheduledTask *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcScheduledTask_OptionalAssertValid(_instance_)
+#else
+# define parcScheduledTask_OptionalAssertValid(_instance_) parcScheduledTask_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCScheduledTask` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * parcScheduledTask_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcScheduledTask_Release(&b);
+ * }
+ * @endcode
+ */
+void parcScheduledTask_AssertValid(const PARCScheduledTask *instance);
+
+/**
+ * Create an instance of PARCScheduledTask
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCScheduledTask instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCScheduledTask *parcScheduledTask_Create(PARCFutureTask *task, uint64_t executionTime);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ * @param [in] other A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ * PARCScheduledTask *b = parcScheduledTask_Create();
+ *
+ * if (parcScheduledTask_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcScheduledTask_Release(&a);
+ * parcScheduledTask_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcScheduledTask_Equals
+ */
+int parcScheduledTask_Compare(const PARCScheduledTask *instance, const PARCScheduledTask *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCScheduledTask` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * PARCScheduledTask *copy = parcScheduledTask_Copy(&b);
+ *
+ * parcScheduledTask_Release(&b);
+ * parcScheduledTask_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCScheduledTask *parcScheduledTask_Copy(const PARCScheduledTask *original);
+
+/**
+ * Print a human readable representation of the given `PARCScheduledTask`.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * parcScheduledTask_Display(a, 0);
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+void parcScheduledTask_Display(const PARCScheduledTask *instance, int indentation);
+
+/**
+ * Determine if two `PARCScheduledTask` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCScheduledTask` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcScheduledTask_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcScheduledTask_Equals(x, y)` must return true if and only if
+ * `parcScheduledTask_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcScheduledTask_Equals(x, y)` returns true and
+ * `parcScheduledTask_Equals(y, z)` returns true,
+ * then `parcScheduledTask_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcScheduledTask_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcScheduledTask_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCScheduledTask instance.
+ * @param [in] y A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ * PARCScheduledTask *b = parcScheduledTask_Create();
+ *
+ * if (parcScheduledTask_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcScheduledTask_Release(&a);
+ * parcScheduledTask_Release(&b);
+ * }
+ * @endcode
+ * @see parcScheduledTask_HashCode
+ */
+bool parcScheduledTask_Equals(const PARCScheduledTask *x, const PARCScheduledTask *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcScheduledTask_Equals} method,
+ * then calling the {@link parcScheduledTask_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcScheduledTask_Equals} function,
+ * then calling the `parcScheduledTask_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * PARCHashCode hashValue = parcScheduledTask_HashCode(buffer);
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcScheduledTask_HashCode(const PARCScheduledTask *instance);
+
+/**
+ * Determine if an instance of `PARCScheduledTask` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * if (parcScheduledTask_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcScheduledTask_IsValid(const PARCScheduledTask *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCScheduledTask` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+void parcScheduledTask_Release(PARCScheduledTask **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * PARCJSON *json = parcScheduledTask_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcScheduledTask_ToJSON(const PARCScheduledTask *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCScheduledTask`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * char *string = parcScheduledTask_ToString(a);
+ *
+ * parcScheduledTask_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcScheduledTask_Display
+ */
+char *parcScheduledTask_ToString(const PARCScheduledTask *instance);
+
+/**
+ * Returns the remaining delay associated with this object.
+ *
+ * @param [in] task A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return the remaining delay; zero or negative values indicate that the delay has already elapsed
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcScheduledTask_GetExecutionTime(const PARCScheduledTask *task);
+
+/**
+ * Attempts to cancel execution of this task.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcScheduledTask_Cancel(PARCScheduledTask *task, bool mayInterruptIfRunning);
+
+/**
+ * Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFutureTaskResult parcScheduledTask_Get(const PARCScheduledTask *task, const PARCTimeout *timeout);
+
+
+void *parcScheduledTask_Run(const PARCScheduledTask *task);
+
+
+/**
+ * Get the `PARCFutureTask` instance for the given `PARCScheduledTask`
+ *
+ * @param [in] task A pointer to a valid `PARCScheduledTask` instance.
+ *
+ * @return the `PARCFutureTask` instance for the given `PARCScheduledTask`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFutureTask *parcScheduledTask_GetTask(const PARCScheduledTask *task);
+
+/**
+ * Returns true if this task was cancelled before it completed normally.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcScheduledTask_IsCancelled(const PARCScheduledTask *task);
+
+/**
+ * Returns true if this task completed.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcScheduledTask_IsDone(const PARCScheduledTask *task);
+#endif
diff --git a/libparc/parc/concurrent/parc_ScheduledThreadPool.c b/libparc/parc/concurrent/parc_ScheduledThreadPool.c
new file mode 100644
index 00000000..3d6c3e57
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ScheduledThreadPool.c
@@ -0,0 +1,323 @@
+/*
+ * 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 <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SortedList.h>
+#include <parc/algol/parc_LinkedList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+
+#include <parc/concurrent/parc_ScheduledThreadPool.h>
+#include <parc/concurrent/parc_Thread.h>
+#include <parc/concurrent/parc_ThreadPool.h>
+
+struct PARCScheduledThreadPool {
+ bool continueExistingPeriodicTasksAfterShutdown;
+ bool executeExistingDelayedTasksAfterShutdown;
+ bool removeOnCancel;
+ PARCSortedList *workQueue;
+ PARCThread *workerThread;
+ PARCThreadPool *threadPool;
+ int poolSize;
+};
+
+static void *
+_workerThread(PARCThread *thread, PARCScheduledThreadPool *pool)
+{
+ while (parcThread_IsCancelled(thread) == false) {
+ if (parcSortedList_Lock(pool->workQueue)) {
+ if (parcSortedList_Size(pool->workQueue) > 0) {
+ PARCScheduledTask *task = parcSortedList_GetFirst(pool->workQueue);
+ int64_t executionDelay = parcScheduledTask_GetExecutionTime(task) - parcTime_NowNanoseconds();
+ if (task != NULL && executionDelay <= 0) {
+ parcSortedList_RemoveFirst(pool->workQueue);
+ parcSortedList_Unlock(pool->workQueue);
+ parcThreadPool_Execute(pool->threadPool, parcScheduledTask_GetTask(task));
+ parcScheduledTask_Release(&task);
+ parcSortedList_Lock(pool->workQueue);
+
+ parcSortedList_Notify(pool->workQueue);
+ } else {
+ parcSortedList_WaitFor(pool->workQueue, executionDelay);
+ }
+ } else {
+ parcSortedList_Wait(pool->workQueue);
+ }
+ }
+ parcSortedList_Unlock(pool->workQueue);
+ }
+
+ return NULL;
+}
+
+static bool
+_parcScheduledThreadPool_Destructor(PARCScheduledThreadPool **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCScheduledThreadPool pointer.");
+ PARCScheduledThreadPool *pool = *instancePtr;
+ parcThreadPool_Release(&pool->threadPool);
+
+ parcThread_Release(&pool->workerThread);
+
+ if (parcObject_Lock(pool->workQueue)) {
+ parcSortedList_Release(&pool->workQueue);
+ } else {
+ assertTrue(false, "Cannot lock the work queue.");
+ }
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcScheduledThreadPool, PARCScheduledThreadPool);
+
+parcObject_ImplementRelease(parcScheduledThreadPool, PARCScheduledThreadPool);
+
+parcObject_Override(PARCScheduledThreadPool, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcScheduledThreadPool_Destructor,
+ .copy = (PARCObjectCopy *) parcScheduledThreadPool_Copy,
+ .toString = (PARCObjectToString *) parcScheduledThreadPool_ToString,
+ .equals = (PARCObjectEquals *) parcScheduledThreadPool_Equals,
+ .compare = (PARCObjectCompare *) parcScheduledThreadPool_Compare,
+ .hashCode = (PARCObjectHashCode *) parcScheduledThreadPool_HashCode);
+
+void
+parcScheduledThreadPool_AssertValid(const PARCScheduledThreadPool *instance)
+{
+ assertTrue(parcScheduledThreadPool_IsValid(instance),
+ "PARCScheduledThreadPool is not valid.");
+}
+
+PARCScheduledThreadPool *
+parcScheduledThreadPool_Create(int poolSize)
+{
+ PARCScheduledThreadPool *result = parcObject_CreateInstance(PARCScheduledThreadPool);
+
+ if (result != NULL) {
+ result->poolSize = poolSize;
+ result->workQueue = parcSortedList_Create();
+ result->threadPool = parcThreadPool_Create(poolSize);
+
+ result->continueExistingPeriodicTasksAfterShutdown = false;
+ result->executeExistingDelayedTasksAfterShutdown = false;
+ result->removeOnCancel = true;
+
+ if (parcObject_Lock(result)) {
+ result->workerThread = parcThread_Create((void *(*)(PARCThread *, PARCObject *))_workerThread, (PARCObject *) result);
+ parcThread_Start(result->workerThread);
+ parcObject_Unlock(result);
+ }
+ }
+
+ return result;
+}
+
+int
+parcScheduledThreadPool_Compare(const PARCScheduledThreadPool *instance, const PARCScheduledThreadPool *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCScheduledThreadPool *
+parcScheduledThreadPool_Copy(const PARCScheduledThreadPool *original)
+{
+ PARCScheduledThreadPool *result = parcScheduledThreadPool_Create(original->poolSize);
+
+ return result;
+}
+
+void
+parcScheduledThreadPool_Display(const PARCScheduledThreadPool *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCScheduledThreadPool@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcScheduledThreadPool_Equals(const PARCScheduledThreadPool *x, const PARCScheduledThreadPool *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->poolSize == y->poolSize) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcScheduledThreadPool_HashCode(const PARCScheduledThreadPool *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcScheduledThreadPool_IsValid(const PARCScheduledThreadPool *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcScheduledThreadPool_ToJSON(const PARCScheduledThreadPool *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcScheduledThreadPool_ToString(const PARCScheduledThreadPool *instance)
+{
+ char *result = parcMemory_Format("PARCScheduledThreadPool@%p\n", instance);
+
+ return result;
+}
+
+void
+parcScheduledThreadPool_Execute(PARCScheduledThreadPool *pool, PARCFutureTask *command)
+{
+}
+
+bool
+parcScheduledThreadPool_GetContinueExistingPeriodicTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool)
+{
+ return pool->continueExistingPeriodicTasksAfterShutdown;
+}
+
+bool
+parcScheduledThreadPool_GetExecuteExistingDelayedTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool)
+{
+ return pool->executeExistingDelayedTasksAfterShutdown;
+}
+
+PARCSortedList *
+parcScheduledThreadPool_GetQueue(const PARCScheduledThreadPool *pool)
+{
+ return pool->workQueue;
+}
+
+bool
+parcScheduledThreadPool_GetRemoveOnCancelPolicy(const PARCScheduledThreadPool *pool)
+{
+ return pool->removeOnCancel;
+}
+
+PARCScheduledTask *
+parcScheduledThreadPool_Schedule(PARCScheduledThreadPool *pool, PARCFutureTask *task, const PARCTimeout *delay)
+{
+ uint64_t executionTime = parcTime_NowNanoseconds() + parcTimeout_InNanoSeconds(delay);
+
+ PARCScheduledTask *scheduledTask = parcScheduledTask_Create(task, executionTime);
+
+ if (parcSortedList_Lock(pool->workQueue)) {
+ parcSortedList_Add(pool->workQueue, scheduledTask);
+ parcScheduledTask_Release(&scheduledTask);
+ parcSortedList_Notify(pool->workQueue);
+ parcSortedList_Unlock(pool->workQueue);
+ }
+ return scheduledTask;
+}
+
+PARCScheduledTask *
+parcScheduledThreadPool_ScheduleAtFixedRate(PARCScheduledThreadPool *pool, PARCFutureTask *task, PARCTimeout initialDelay, PARCTimeout period)
+{
+ return NULL;
+}
+
+PARCScheduledTask *
+parcScheduledThreadPool_ScheduleWithFixedDelay(PARCScheduledThreadPool *pool, PARCFutureTask *task, PARCTimeout initialDelay, PARCTimeout delay)
+{
+ return NULL;
+}
+
+void
+parcScheduledThreadPool_SetContinueExistingPeriodicTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool, bool value)
+{
+}
+
+void
+parcScheduledThreadPool_SetExecuteExistingDelayedTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool, bool value)
+{
+}
+
+void
+parcScheduledThreadPool_SetRemoveOnCancelPolicy(PARCScheduledThreadPool *pool, bool value)
+{
+}
+
+void
+parcScheduledThreadPool_Shutdown(PARCScheduledThreadPool *pool)
+{
+ parcScheduledThreadPool_ShutdownNow(pool);
+}
+
+PARCList *
+parcScheduledThreadPool_ShutdownNow(PARCScheduledThreadPool *pool)
+{
+ parcThread_Cancel(pool->workerThread);
+
+ parcThreadPool_ShutdownNow(pool->threadPool);
+
+ // Wake them all up so they detect that they are cancelled.
+ if (parcObject_Lock(pool)) {
+ parcObject_NotifyAll(pool);
+ parcObject_Unlock(pool);
+ }
+ if (parcObject_Lock(pool->workQueue)) {
+ parcObject_NotifyAll(pool->workQueue);
+ parcObject_Unlock(pool->workQueue);
+ }
+
+ parcThread_Join(pool->workerThread);
+
+ return NULL;
+}
+
+PARCScheduledTask *
+parcScheduledThreadPool_Submit(PARCScheduledThreadPool *pool, PARCFutureTask *task)
+{
+ PARCScheduledTask *scheduledTask = parcScheduledTask_Create(task, 0);
+
+ parcSortedList_Add(pool->workQueue, scheduledTask);
+
+ return scheduledTask;
+}
diff --git a/libparc/parc/concurrent/parc_ScheduledThreadPool.h b/libparc/parc/concurrent/parc_ScheduledThreadPool.h
new file mode 100755
index 00000000..36c26909
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ScheduledThreadPool.h
@@ -0,0 +1,429 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_ScheduledThreadPool.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_ScheduledThreadPool
+#define PARCLibrary_parc_ScheduledThreadPool
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_SortedList.h>
+#include <parc/concurrent/parc_FutureTask.h>
+#include <parc/concurrent/parc_ScheduledTask.h>
+#include <parc/concurrent/parc_Timeout.h>
+
+struct PARCScheduledThreadPool;
+typedef struct PARCScheduledThreadPool PARCScheduledThreadPool;
+
+/**
+ * Increase the number of references to a `PARCScheduledThreadPool` instance.
+ *
+ * Note that new `PARCScheduledThreadPool` is not created,
+ * only that the given `PARCScheduledThreadPool` reference count is incremented.
+ * Discard the reference by invoking `parcScheduledThreadPool_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * PARCScheduledThreadPool *b = parcScheduledThreadPool_Acquire();
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * parcScheduledThreadPool_Release(&b);
+ * }
+ * @endcode
+ */
+PARCScheduledThreadPool *parcScheduledThreadPool_Acquire(const PARCScheduledThreadPool *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcScheduledThreadPool_OptionalAssertValid(_instance_)
+#else
+# define parcScheduledThreadPool_OptionalAssertValid(_instance_) parcScheduledThreadPool_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCScheduledThreadPool` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * parcScheduledThreadPool_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcScheduledThreadPool_Release(&b);
+ * }
+ * @endcode
+ */
+void parcScheduledThreadPool_AssertValid(const PARCScheduledThreadPool *instance);
+
+/**
+ * Create an instance of PARCScheduledThreadPool
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCScheduledThreadPool instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCScheduledThreadPool *parcScheduledThreadPool_Create(int poolSize);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ * @param [in] other A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ * PARCScheduledThreadPool *b = parcScheduledThreadPool_Create();
+ *
+ * if (parcScheduledThreadPool_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * parcScheduledThreadPool_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcScheduledThreadPool_Equals
+ */
+int parcScheduledThreadPool_Compare(const PARCScheduledThreadPool *instance, const PARCScheduledThreadPool *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCScheduledThreadPool` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * PARCScheduledThreadPool *copy = parcScheduledThreadPool_Copy(&b);
+ *
+ * parcScheduledThreadPool_Release(&b);
+ * parcScheduledThreadPool_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCScheduledThreadPool *parcScheduledThreadPool_Copy(const PARCScheduledThreadPool *original);
+
+/**
+ * Print a human readable representation of the given `PARCScheduledThreadPool`.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * parcScheduledThreadPool_Display(a, 0);
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcScheduledThreadPool_Display(const PARCScheduledThreadPool *instance, int indentation);
+
+/**
+ * Determine if two `PARCScheduledThreadPool` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCScheduledThreadPool` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcScheduledThreadPool_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcScheduledThreadPool_Equals(x, y)` must return true if and only if
+ * `parcScheduledThreadPool_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcScheduledThreadPool_Equals(x, y)` returns true and
+ * `parcScheduledThreadPool_Equals(y, z)` returns true,
+ * then `parcScheduledThreadPool_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcScheduledThreadPool_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcScheduledThreadPool_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCScheduledThreadPool instance.
+ * @param [in] y A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ * PARCScheduledThreadPool *b = parcScheduledThreadPool_Create();
+ *
+ * if (parcScheduledThreadPool_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * parcScheduledThreadPool_Release(&b);
+ * }
+ * @endcode
+ * @see parcScheduledThreadPool_HashCode
+ */
+bool parcScheduledThreadPool_Equals(const PARCScheduledThreadPool *x, const PARCScheduledThreadPool *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcScheduledThreadPool_Equals} method,
+ * then calling the {@link parcScheduledThreadPool_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcScheduledThreadPool_Equals} function,
+ * then calling the `parcScheduledThreadPool_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * PARCHashCode hashValue = parcScheduledThreadPool_HashCode(buffer);
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcScheduledThreadPool_HashCode(const PARCScheduledThreadPool *instance);
+
+/**
+ * Determine if an instance of `PARCScheduledThreadPool` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * if (parcScheduledThreadPool_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcScheduledThreadPool_IsValid(const PARCScheduledThreadPool *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCScheduledThreadPool` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcScheduledThreadPool_Release(PARCScheduledThreadPool **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * PARCJSON *json = parcScheduledThreadPool_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcScheduledThreadPool_ToJSON(const PARCScheduledThreadPool *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCScheduledThreadPool`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * char *string = parcScheduledThreadPool_ToString(a);
+ *
+ * parcScheduledThreadPool_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcScheduledThreadPool_Display
+ */
+char *parcScheduledThreadPool_ToString(const PARCScheduledThreadPool *instance);
+
+/**
+ * Executes command with zero required delay.
+ */
+void parcScheduledThreadPool_Execute(PARCScheduledThreadPool *pool, PARCFutureTask *command);
+
+/**
+ * Gets the policy on whether to continue executing existing periodic tasks even when this executor has been shutdown.
+ */
+bool parcScheduledThreadPool_GetContinueExistingPeriodicTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool);
+
+/**
+ * Gets the policy on whether to execute existing delayed tasks even when this executor has been shutdown.
+ */
+bool parcScheduledThreadPool_GetExecuteExistingDelayedTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool);
+
+/**
+ * Returns the task queue used by this executor.
+ */
+PARCSortedList *parcScheduledThreadPool_GetQueue(const PARCScheduledThreadPool *pool);
+
+/**
+ * Gets the policy on whether cancelled tasks should be immediately removed from the work queue at time of cancellation.
+ */
+bool parcScheduledThreadPool_GetRemoveOnCancelPolicy(const PARCScheduledThreadPool *pool);
+
+/**
+ * Creates and executes a one-shot action that becomes enabled after the given delay.
+ */
+PARCScheduledTask *parcScheduledThreadPool_Schedule(PARCScheduledThreadPool *pool, PARCFutureTask *task, const PARCTimeout *delay);
+
+/**
+ * Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
+ */
+PARCScheduledTask *parcScheduledThreadPool_ScheduleAtFixedRate(PARCScheduledThreadPool *pool, PARCFutureTask *task, PARCTimeout initialDelay, PARCTimeout period);
+
+/**
+ * Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next.
+ */
+PARCScheduledTask *parcScheduledThreadPool_ScheduleWithFixedDelay(PARCScheduledThreadPool *pool, PARCFutureTask *task, PARCTimeout initialDelay, PARCTimeout delay);
+
+/**
+ * Sets the policy on whether to continue executing existing periodic tasks even when this executor has been shutdown.
+ */
+void parcScheduledThreadPool_SetContinueExistingPeriodicTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool, bool value);
+
+/**
+ * Sets the policy on whether to execute existing delayed tasks even when this executor has been shutdown.
+ */
+void parcScheduledThreadPool_SetExecuteExistingDelayedTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool, bool value);
+
+/**
+ * Sets the policy on whether cancelled tasks should be immediately removed from the work queue at time of cancellation.
+ */
+void parcScheduledThreadPool_SetRemoveOnCancelPolicy(PARCScheduledThreadPool *pool, bool value);
+
+/**
+ * Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
+ */
+void parcScheduledThreadPool_Shutdown(PARCScheduledThreadPool *pool);
+
+/**
+ * Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
+ */
+PARCList *parcScheduledThreadPool_ShutdownNow(PARCScheduledThreadPool *pool);
+
+/**
+ * Submits a PARCFutureTask task for execution and returns the PARCFutureTask representing that task.
+ */
+PARCScheduledTask *parcScheduledThreadPool_Submit(PARCScheduledThreadPool *pool, PARCFutureTask *task);
+#endif
diff --git a/libparc/parc/concurrent/parc_Synchronizer.c b/libparc/parc/concurrent/parc_Synchronizer.c
new file mode 100755
index 00000000..c4475476
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Synchronizer.c
@@ -0,0 +1,146 @@
+/*
+ * 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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/concurrent/parc_Synchronizer.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+# include <pthread.h>
+#else
+//# include <pthread.h>
+#endif
+
+typedef enum {
+ _PARCSynchronizer_Unlocked = 0,
+ _PARCSynchronizer_Locked = 1
+} _PARCSynchronizer;
+
+struct PARCSynchronizer {
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#else
+ int mutex;
+#endif
+};
+
+static void
+_parcSynchronizer_Finalize(PARCSynchronizer **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSynchronizer pointer.");
+
+ parcSynchronizer_OptionalAssertValid((*instancePtr));
+}
+
+parcObject_ImplementAcquire(parcSynchronizer, PARCSynchronizer);
+
+parcObject_ImplementRelease(parcSynchronizer, PARCSynchronizer);
+
+parcObject_ExtendPARCObject(PARCSynchronizer, _parcSynchronizer_Finalize, NULL, NULL, NULL, NULL, NULL, NULL);
+
+void
+parcSynchronizer_AssertValid(const PARCSynchronizer *instance)
+{
+ assertTrue(parcSynchronizer_IsValid(instance),
+ "PARCSynchronizer is not valid.");
+}
+
+PARCSynchronizer *
+parcSynchronizer_Create(void)
+{
+ PARCSynchronizer *result = parcObject_CreateInstance(PARCSynchronizer);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+#else
+ result->mutex = _PARCSynchronizer_Unlocked;
+#endif
+
+ return result;
+}
+
+void
+parcSynchronizer_Display(const PARCSynchronizer *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCSynchronizer@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcSynchronizer_IsValid(const PARCSynchronizer *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+bool
+parcSynchronizer_TryLock(PARCSynchronizer *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ bool result = pthread_mutex_trylock(&instance->mutex) == 0;
+#else
+ bool result = __sync_bool_compare_and_swap(&instance->mutex, _PARCSynchronizer_Unlocked, _PARCSynchronizer_Locked);
+#endif
+ return result;
+}
+
+void
+parcSynchronizer_Lock(PARCSynchronizer *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&instance->mutex);
+#else
+ while (!__sync_bool_compare_and_swap(&instance->mutex, _PARCSynchronizer_Unlocked, _PARCSynchronizer_Locked)) {
+ ;
+ }
+#endif
+}
+
+void
+parcSynchronizer_Unlock(PARCSynchronizer *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_unlock(&instance->mutex);
+#else
+ while (!__sync_bool_compare_and_swap(&instance->mutex, _PARCSynchronizer_Locked, _PARCSynchronizer_Unlocked)) {
+ ;
+ }
+#endif
+}
+
+bool
+parcSynchronizer_IsLocked(const PARCSynchronizer *barrier)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ PARCSynchronizer *instance = (PARCSynchronizer *) barrier;
+
+ bool result = pthread_mutex_trylock(&instance->mutex) != 0;
+ pthread_mutex_unlock(&instance->mutex);
+ return result;
+#else
+ return barrier->mutex == _PARCSynchronizer_Locked;
+#endif
+}
diff --git a/libparc/parc/concurrent/parc_Synchronizer.h b/libparc/parc/concurrent/parc_Synchronizer.h
new file mode 100755
index 00000000..a387888f
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Synchronizer.h
@@ -0,0 +1,277 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_Synchronizer.h
+ * @ingroup threading
+ * @brief A simple mutual exclusive synchronization implementation.
+ *
+ * Detailed Description
+ *
+ */
+#ifndef PARCLibrary_parc_Barrier
+#define PARCLibrary_parc_Barrier
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+
+struct PARCSynchronizer;
+typedef struct PARCSynchronizer PARCSynchronizer;
+
+/**
+ * Increase the number of references to a `PARCSynchronizer` instance.
+ *
+ * Note that new `PARCSynchronizer` is not created,
+ * only that the given `PARCSynchronizer` reference count is incremented.
+ * Discard the reference by invoking `parcSynchronizer_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * PARCSynchronizer *b = parcSynchronizer_Acquire();
+ *
+ * parcSynchronizer_Release(&a);
+ * parcSynchronizer_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSynchronizer *parcSynchronizer_Acquire(const PARCSynchronizer *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcSynchronizer_OptionalAssertValid(_instance_)
+#else
+# define parcSynchronizer_OptionalAssertValid(_instance_) parcSynchronizer_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCSynchronizer` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * parcSynchronizer_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcSynchronizer_Release(&b);
+ * }
+ * @endcode
+ */
+void parcSynchronizer_AssertValid(const PARCSynchronizer *instance);
+
+/**
+ * Create an instance of PARCSynchronizer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCSynchronizer instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSynchronizer *parcSynchronizer_Create(void);
+
+/**
+ * Print a human readable representation of the given `PARCSynchronizer`.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * parcSynchronizer_Display(a, 0);
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSynchronizer_Display(const PARCSynchronizer *instance, int indentation);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcSynchronizer_Equals} method,
+ * then calling the {@link parcSynchronizer_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcSynchronizer_Equals} function,
+ * then calling the `parcSynchronizer_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * uint32_t hashValue = parcSynchronizer_HashCode(buffer);
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+int parcSynchronizer_HashCode(const PARCSynchronizer *instance);
+
+/**
+ * Determine if an instance of `PARCSynchronizer` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * if (parcSynchronizer_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcSynchronizer_IsValid(const PARCSynchronizer *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSynchronizer` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSynchronizer_Release(PARCSynchronizer **instancePtr);
+
+/**
+ * Attempt to lock the given PARCSynchronizer.
+ *
+ * If the synchronizer is already locked, this function returns `false`.
+ * Otherwise, the lock is established and this function returns `true`.
+ *
+ * @param [in] barrier A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return `true` The PARCSynchronizer was successfully set.
+ * @return `false` The PARCSynchronizer could not be set.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcSynchronizer_TryLock(PARCSynchronizer *barrier);
+
+/**
+ * Lock the given PARCSynchronizer.
+ *
+ * If the synchronizer is already locked, this function blocks the caller until it is able to acquire the lock.
+ *
+ * @param [in] barrier A pointer to a valid PARCSynchronizer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcSynchronizer_Lock(PARCSynchronizer *barrier);
+
+/**
+ * Unlock the given PARCSynchronizer.
+ *
+ * @param [in] barrier A pointer to a valid PARCSynchronizer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcSynchronizer_Unlock(PARCSynchronizer *barrier);
+
+/**
+ * Check if a PARCSynchronizer is locked.
+ *
+ * @param [in] synchronizer A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return true The specified synchronizer is currently locked.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * if (parcSynchronizer_IsLocked(a) == true) {
+ * printf("A PARCSynchronizer cannot be created in the locked state.\n");
+ * }
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+bool parcSynchronizer_IsLocked(const PARCSynchronizer *synchronizer);
+#endif
diff --git a/libparc/parc/concurrent/parc_Thread.c b/libparc/parc/concurrent/parc_Thread.c
new file mode 100644
index 00000000..4bccc47f
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Thread.c
@@ -0,0 +1,232 @@
+/*
+ * 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 <pthread.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/concurrent/parc_Thread.h>
+
+struct PARCThread {
+ void *(*run)(PARCThread *, PARCObject *param);
+ PARCObject *argument;
+ bool isCancelled;
+ bool isRunning;
+ pthread_t thread;
+};
+
+static bool
+_parcThread_Destructor(PARCThread **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCThread pointer.");
+ PARCThread *thread = *instancePtr;
+
+ if (thread->argument != NULL) {
+ parcObject_Release(&thread->argument);
+ }
+
+ thread->isCancelled = true;
+ parcThread_Join(thread);
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcThread, PARCThread);
+
+parcObject_ImplementRelease(parcThread, PARCThread);
+
+parcObject_Override(PARCThread, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcThread_Destructor,
+ .copy = (PARCObjectCopy *) parcThread_Copy,
+ .toString = (PARCObjectToString *) parcThread_ToString,
+ .equals = (PARCObjectEquals *) parcThread_Equals,
+ .compare = (PARCObjectCompare *) parcThread_Compare,
+ .hashCode = (PARCObjectHashCode *) parcThread_HashCode,
+ .display = (PARCObjectDisplay *) parcThread_Display
+ );
+
+void
+parcThread_AssertValid(const PARCThread *instance)
+{
+ assertTrue(parcThread_IsValid(instance),
+ "PARCThread is not valid.");
+}
+
+PARCThread *
+parcThread_Create(void *(*runFunction)(PARCThread *, PARCObject *), PARCObject *restrict parameter)
+{
+ assertNotNull(parameter, "Parameter cannot be NULL.");
+
+ PARCThread *result = parcObject_CreateAndClearInstance(PARCThread);
+
+ if (result) {
+ result->run = runFunction;
+ result->argument = parcObject_Acquire(parameter);
+ result->isCancelled = false;
+ result->isRunning = false;
+ }
+
+ return result;
+}
+
+int
+parcThread_Compare(const PARCThread *instance, const PARCThread *other)
+{
+ int result = 0;
+ return result;
+}
+
+PARCThread *
+parcThread_Copy(const PARCThread *original)
+{
+ PARCThread *result = parcThread_Create(original->run, original->argument);
+ result->isCancelled = original->isCancelled;
+ result->isRunning = original->isRunning;
+
+ return result;
+}
+
+void
+parcThread_Display(const PARCThread *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCThread@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcThread_Equals(const PARCThread *x, const PARCThread *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ result = pthread_equal(x->thread, y->thread);
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcThread_HashCode(const PARCThread *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcThread_IsValid(const PARCThread *thread)
+{
+ bool result = false;
+
+ if (thread != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcThread_ToJSON(const PARCThread *thread)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+parcThread_ToString(const PARCThread *thread)
+{
+ char *result = parcMemory_Format("PARCThread@%p{.id=%p, .isCancelled=%s}", thread, thread->thread, thread->isCancelled ? "true" : "false");
+
+ return result;
+}
+
+static void *
+_parcThread_Run(PARCThread *thread)
+{
+ thread->isRunning = true;
+ thread->run(thread, thread->argument);
+ thread->isRunning = false;
+
+ // The thread is done, release the reference to the argument acquired when this PARCThread was created.
+ // This prevents the reference from lingering leading to memory leaks if the thread is not properly joined.
+ if (thread->argument != NULL) {
+ parcObject_Release(&thread->argument);
+ }
+ // Release the thread reference that was acquired *before* this thread was started.
+ parcThread_Release(&thread);
+
+ return NULL;
+}
+
+void
+parcThread_Start(PARCThread *thread)
+{
+ PARCThread *parameter = parcThread_Acquire(thread);
+ pthread_create(&thread->thread, NULL, (void *(*)(void *))_parcThread_Run, parameter);
+}
+
+PARCObject *
+parcThread_GetParameter(const PARCThread *thread)
+{
+ return thread->argument;
+}
+
+bool
+parcThread_Cancel(PARCThread *thread)
+{
+ if (parcThread_Lock(thread)) {
+ thread->isCancelled = true;
+ parcThread_Notify(thread);
+ parcThread_Unlock(thread);
+ }
+ return true;
+}
+
+int
+parcThread_GetId(const PARCThread *thread)
+{
+ return (int) thread->thread;
+}
+
+bool
+parcThread_IsRunning(const PARCThread *thread)
+{
+ return thread->isRunning;
+}
+
+bool
+parcThread_IsCancelled(const PARCThread *thread)
+{
+ return thread->isCancelled;
+}
+
+void
+parcThread_Join(PARCThread *thread)
+{
+ pthread_join(thread->thread, NULL);
+}
diff --git a/libparc/parc/concurrent/parc_Thread.h b/libparc/parc/concurrent/parc_Thread.h
new file mode 100755
index 00000000..f24306ae
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Thread.h
@@ -0,0 +1,601 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_Thread.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_Thread
+#define PARCLibrary_parc_Thread
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct PARCThread;
+typedef struct PARCThread PARCThread;
+
+/**
+ * Increase the number of references to a `PARCThread` instance.
+ *
+ * Note that new `PARCThread` is not created,
+ * only that the given `PARCThread` reference count is incremented.
+ * Discard the reference by invoking `parcThread_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * PARCThread *b = parcThread_Acquire();
+ *
+ * parcThread_Release(&a);
+ * parcThread_Release(&b);
+ * }
+ * @endcode
+ */
+PARCThread *parcThread_Acquire(const PARCThread *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcThread_OptionalAssertValid(_instance_)
+#else
+# define parcThread_OptionalAssertValid(_instance_) parcThread_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCThread` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * parcThread_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcThread_Release(&b);
+ * }
+ * @endcode
+ */
+void parcThread_AssertValid(const PARCThread *instance);
+
+/**
+ * Create an instance of PARCThread
+ *
+ * @return non-NULL A pointer to a valid PARCThread instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * MyTask *task = myTask_Create();
+ * PARCThread *thread = parcThread_Create(myTask_Run, myTask);
+ *
+ * parcThread_Start(a);
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+//#define parcThread_Create(_runFunction_, _argument_) parcThread_CreateImpl((void (*)(PARCObject *)) _runFunction_, (PARCObject *) _argument_)
+
+PARCThread *parcThread_Create(void *(*run)(PARCThread *, PARCObject *), PARCObject *restrict argument);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ * @param [in] other A pointer to a valid PARCThread instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ * PARCThread *b = parcThread_Create();
+ *
+ * if (parcThread_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcThread_Release(&a);
+ * parcThread_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcThread_Equals
+ */
+int parcThread_Compare(const PARCThread *instance, const PARCThread *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCThread instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCThread` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * PARCThread *copy = parcThread_Copy(&b);
+ *
+ * parcThread_Release(&b);
+ * parcThread_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCThread *parcThread_Copy(const PARCThread *original);
+
+/**
+ * Print a human readable representation of the given `PARCThread`.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * parcThread_Display(a, 0);
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+void parcThread_Display(const PARCThread *instance, int indentation);
+
+/**
+ * Determine if two `PARCThread` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCThread` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcThread_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcThread_Equals(x, y)` must return true if and only if
+ * `parcThread_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcThread_Equals(x, y)` returns true and
+ * `parcThread_Equals(y, z)` returns true,
+ * then `parcThread_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcThread_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcThread_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCThread instance.
+ * @param [in] y A pointer to a valid PARCThread instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ * PARCThread *b = parcThread_Create();
+ *
+ * if (parcThread_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcThread_Release(&a);
+ * parcThread_Release(&b);
+ * }
+ * @endcode
+ * @see parcThread_HashCode
+ */
+bool parcThread_Equals(const PARCThread *x, const PARCThread *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcThread_Equals} method,
+ * then calling the {@link parcThread_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcThread_Equals} function,
+ * then calling the `parcThread_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * PARCHashCode hashValue = parcThread_HashCode(buffer);
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcThread_HashCode(const PARCThread *instance);
+
+/**
+ * Determine if an instance of `PARCThread` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * if (parcThread_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcThread_IsValid(const PARCThread *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCThread` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+void parcThread_Release(PARCThread **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * PARCJSON *json = parcThread_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcThread_ToJSON(const PARCThread *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCThread`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * char *string = parcThread_ToString(a);
+ *
+ * parcThread_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcThread_Display
+ */
+char *parcThread_ToString(const PARCThread *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcLinkedList_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCThread instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcThread_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcThread, PARCThread);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcHashMap_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCThread` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcThread_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcThread, PARCThread);
+
+/**
+ * Obtain the lock on the given `PARCThread` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCThread` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCThread` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcThread_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcThread, PARCThread);
+
+/**
+ * Try to obtain the advisory lock on the given PARCThread instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCThread instance.
+ *
+ * @return true The PARCThread is locked.
+ * @return false The PARCThread is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcThread_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcThread, PARCThread);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCHashMap` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCThread` instance.
+ *
+ * @return true The `PARCThread` was locked and now is unlocked.
+ * @return false The `PARCThread` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcThread_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcThread, PARCThread);
+
+/**
+ * Determine if the advisory lock on the given `PARCThread` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCThread` instance.
+ *
+ * @return true The `PARCThread` is locked.
+ * @return false The `PARCThread` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcThread_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcThread, PARCThread);
+
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcThread_Start(PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCObject *parcThread_GetParameter(const PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcThread_Cancel(PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcThread_IsCancelled(const PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcThread_IsRunning(const PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int parcThread_GetId(const PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcThread_Join(PARCThread *thread);
+#endif
diff --git a/libparc/parc/concurrent/parc_ThreadPool.c b/libparc/parc/concurrent/parc_ThreadPool.c
new file mode 100644
index 00000000..80b093ba
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ThreadPool.c
@@ -0,0 +1,457 @@
+/*
+ * 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 <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_SortedList.h>
+#include <parc/algol/parc_LinkedList.h>
+
+#include <parc/concurrent/parc_AtomicUint64.h>
+#include <parc/concurrent/parc_ThreadPool.h>
+#include <parc/concurrent/parc_Thread.h>
+
+struct PARCThreadPool {
+ bool continueExistingPeriodicTasksAfterShutdown;
+ bool executeExistingDelayedTasksAfterShutdown;
+ bool removeOnCancel;
+ PARCLinkedList *workQueue;
+ PARCLinkedList *threads;
+ int poolSize;
+ int maximumPoolSize;
+ long taskCount;
+ bool isShutdown;
+ bool isTerminated;
+ bool isTerminating;
+
+ PARCAtomicUint64 *completedTaskCount;
+};
+
+static void *
+_parcThreadPool_Worker(const PARCThread *thread, const PARCThreadPool *pool)
+{
+ while (parcThread_IsCancelled(thread) == false && pool->isTerminated == false) {
+ if (parcLinkedList_Lock(pool->workQueue)) {
+ PARCFutureTask *task = parcLinkedList_RemoveFirst(pool->workQueue);
+ if (task != NULL) {
+ parcAtomicUint64_Increment(pool->completedTaskCount);
+ parcLinkedList_Unlock(pool->workQueue);
+ parcFutureTask_Run(task);
+ parcFutureTask_Release(&task);
+ parcLinkedList_Lock(pool->workQueue);
+
+ parcLinkedList_Notify(pool->workQueue);
+ } else {
+ parcLinkedList_WaitFor(pool->workQueue, 1000000000);
+ }
+ parcLinkedList_Unlock(pool->workQueue);
+ }
+ }
+
+ return NULL;
+}
+
+static void
+_parcThreadPool_CancelAll(const PARCThreadPool *pool)
+{
+ PARCIterator *iterator = parcLinkedList_CreateIterator(pool->threads);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCThread *thread = parcIterator_Next(iterator);
+ parcThread_Cancel(thread);
+ }
+ parcIterator_Release(&iterator);
+}
+
+static void
+_parcThreadPool_JoinAll(const PARCThreadPool *pool)
+{
+ PARCIterator *iterator = parcLinkedList_CreateIterator(pool->threads);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCThread *thread = parcIterator_Next(iterator);
+ parcThread_Join(thread);
+ }
+ parcIterator_Release(&iterator);
+}
+
+static bool
+_parcThreadPool_Destructor(PARCThreadPool **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCThreadPool pointer.");
+ PARCThreadPool *pool = *instancePtr;
+
+ if (pool->isShutdown == false) {
+ _parcThreadPool_CancelAll(pool);
+ _parcThreadPool_JoinAll(pool);
+ }
+
+ parcAtomicUint64_Release(&pool->completedTaskCount);
+ parcLinkedList_Release(&pool->threads);
+
+ if (parcObject_Lock(pool->workQueue)) {
+ parcLinkedList_Release(&pool->workQueue);
+ }
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcThreadPool, PARCThreadPool);
+
+parcObject_ImplementRelease(parcThreadPool, PARCThreadPool);
+
+parcObject_Override(PARCThreadPool, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcThreadPool_Destructor,
+ .copy = (PARCObjectCopy *) parcThreadPool_Copy,
+ .toString = (PARCObjectToString *) parcThreadPool_ToString,
+ .equals = (PARCObjectEquals *) parcThreadPool_Equals,
+ .compare = (PARCObjectCompare *) parcThreadPool_Compare,
+ .hashCode = (PARCObjectHashCode *) parcThreadPool_HashCode);
+
+void
+parcThreadPool_AssertValid(const PARCThreadPool *instance)
+{
+ assertTrue(parcThreadPool_IsValid(instance),
+ "PARCThreadPool is not valid.");
+}
+
+
+PARCThreadPool *
+parcThreadPool_Create(int poolSize)
+{
+ PARCThreadPool *result = parcObject_CreateInstance(PARCThreadPool);
+
+ if (result != NULL) {
+ result->poolSize = poolSize;
+ result->maximumPoolSize = poolSize;
+ result->taskCount = 0;
+ result->isShutdown = false;
+ result->isTerminated = false;
+ result->isTerminating = false;
+ result->workQueue = parcLinkedList_Create();
+ result->threads = parcLinkedList_Create();
+
+ result->completedTaskCount = parcAtomicUint64_Create(0);
+
+ result->continueExistingPeriodicTasksAfterShutdown = false;
+ result->executeExistingDelayedTasksAfterShutdown = false;
+ result->removeOnCancel = true;
+
+ if (parcObject_Lock(result)) {
+ for (int i = 0; i < poolSize; i++) {
+ PARCThread *thread = parcThread_Create((void *(*)(PARCThread *, PARCObject *))_parcThreadPool_Worker, (PARCObject *) result);
+ parcLinkedList_Append(result->threads, thread);
+ parcThread_Start(thread);
+ parcThread_Release(&thread);
+ }
+ parcObject_Unlock(result);
+ }
+ }
+
+ return result;
+}
+
+int
+parcThreadPool_Compare(const PARCThreadPool *instance, const PARCThreadPool *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCThreadPool *
+parcThreadPool_Copy(const PARCThreadPool *original)
+{
+ PARCThreadPool *result = parcThreadPool_Create(original->poolSize);
+
+ return result;
+}
+
+void
+parcThreadPool_Display(const PARCThreadPool *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCThreadPool@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcThreadPool_Equals(const PARCThreadPool *x, const PARCThreadPool *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ /* perform instance specific equality tests here. */
+ if (x->poolSize == y->poolSize) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcThreadPool_HashCode(const PARCThreadPool *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcThreadPool_IsValid(const PARCThreadPool *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcThreadPool_ToJSON(const PARCThreadPool *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcThreadPool_ToString(const PARCThreadPool *instance)
+{
+ char *result = parcMemory_Format("PARCThreadPool@%p\n", instance);
+
+ return result;
+}
+
+void
+parcThreadPool_SetAllowCoreThreadTimeOut(PARCThreadPool *pool, bool value)
+{
+}
+
+bool
+parcThreadPool_GetAllowsCoreThreadTimeOut(const PARCThreadPool *pool)
+{
+ return false;
+}
+
+bool
+parcThreadPool_AwaitTermination(PARCThreadPool *pool, PARCTimeout *timeout)
+{
+ bool result = false;
+
+ if (pool->isTerminating) {
+ if (parcLinkedList_Lock(pool->workQueue)) {
+ while (parcLinkedList_Size(pool->workQueue) > 0) {
+ if (parcTimeout_IsNever(timeout)) {
+ parcLinkedList_Wait(pool->workQueue);
+ } else {
+ // This is not accurate as this will continue the delay, rather than keep a cumulative amount of delay.
+ uint64_t delay = parcTimeout_InNanoSeconds(timeout);
+ parcLinkedList_WaitFor(pool->workQueue, delay);
+ }
+ }
+ result = true;
+ parcLinkedList_Unlock(pool->workQueue);
+ }
+
+ parcThreadPool_ShutdownNow(pool);
+ }
+
+ return result;
+}
+
+bool
+parcThreadPool_Execute(PARCThreadPool *pool, PARCFutureTask *task)
+{
+ bool result = false;
+
+ if (parcThreadPool_Lock(pool)) {
+ if (pool->isShutdown == false) {
+ parcThreadPool_Unlock(pool);
+ if (parcLinkedList_Lock(pool->workQueue)) {
+ parcLinkedList_Append(pool->workQueue, task);
+ parcLinkedList_Notify(pool->workQueue);
+ parcLinkedList_Unlock(pool->workQueue);
+ result = true;
+ }
+ } else {
+ parcThreadPool_Unlock(pool);
+ }
+ }
+
+ return result;
+}
+
+int
+parcThreadPool_GetActiveCount(const PARCThreadPool *pool)
+{
+ return pool->poolSize;
+}
+
+uint64_t
+parcThreadPool_GetCompletedTaskCount(const PARCThreadPool *pool)
+{
+ return parcAtomicUint64_GetValue(pool->completedTaskCount);
+}
+
+int
+parcThreadPool_GetCorePoolSize(const PARCThreadPool *pool)
+{
+ return pool->poolSize;
+}
+
+PARCTimeout *
+parcThreadPool_GetKeepAliveTime(const PARCThreadPool *pool)
+{
+ return PARCTimeout_Never;
+}
+
+int
+parcThreadPool_GetLargestPoolSize(const PARCThreadPool *pool)
+{
+ return pool->poolSize;
+}
+
+int
+parcThreadPool_GetMaximumPoolSize(const PARCThreadPool *pool)
+{
+ return pool->maximumPoolSize;
+}
+
+int
+parcThreadPool_GetPoolSize(const PARCThreadPool *pool)
+{
+ return pool->poolSize;
+}
+
+PARCLinkedList *
+parcThreadPool_GetQueue(const PARCThreadPool *pool)
+{
+ return pool->workQueue;
+}
+
+long
+parcThreadPool_GetTaskCount(const PARCThreadPool *pool)
+{
+ return pool->taskCount;
+}
+
+bool
+parcThreadPool_IsShutdown(const PARCThreadPool *pool)
+{
+ return pool->isShutdown;
+}
+
+bool
+parcThreadPool_IsTerminated(const PARCThreadPool *pool)
+{
+ return pool->isTerminated;
+}
+
+bool
+parcThreadPool_IsTerminating(const PARCThreadPool *pool)
+{
+ return pool->isTerminating;
+}
+
+int
+parcThreadPool_PrestartAllCoreThreads(PARCThreadPool *pool)
+{
+ return 0;
+}
+
+bool
+parcThreadPool_PrestartCoreThread(PARCThreadPool *pool)
+{
+ return 0;
+}
+
+void
+parcThreadPool_Purge(PARCThreadPool *pool)
+{
+}
+
+bool
+parcThreadPool_Remove(PARCThreadPool *pool, PARCFutureTask *task)
+{
+ return false;
+}
+
+void
+parcThreadPool_SetCorePoolSize(PARCThreadPool *pool, int corePoolSize)
+{
+}
+
+void
+parcThreadPool_SetKeepAliveTime(PARCThreadPool *pool, PARCTimeout *timeout)
+{
+}
+
+void
+parcThreadPool_SetMaximumPoolSize(PARCThreadPool *pool, int maximumPoolSize)
+{
+}
+
+void
+parcThreadPool_Shutdown(PARCThreadPool *pool)
+{
+ if (parcThreadPool_Lock(pool)) {
+ pool->isShutdown = true;
+ pool->isTerminating = true;
+ parcThreadPool_Unlock(pool);
+ }
+}
+
+PARCLinkedList *
+parcThreadPool_ShutdownNow(PARCThreadPool *pool)
+{
+ parcThreadPool_Shutdown(pool);
+
+ // Cause all of the worker threads to exit.
+ _parcThreadPool_CancelAll(pool);
+
+ // Wake them all up so they detect that they are cancelled.
+ if (parcThreadPool_Lock(pool)) {
+ parcThreadPool_NotifyAll(pool);
+ parcThreadPool_Unlock(pool);
+ }
+
+ if (parcLinkedList_Lock(pool->workQueue)) {
+ parcLinkedList_NotifyAll(pool->workQueue);
+ parcLinkedList_Unlock(pool->workQueue);
+ }
+ // Join with all of them, thereby cleaning up all of them.
+ _parcThreadPool_JoinAll(pool);
+
+ pool->isTerminated = true;
+ return NULL;
+}
diff --git a/libparc/parc/concurrent/parc_ThreadPool.h b/libparc/parc/concurrent/parc_ThreadPool.h
new file mode 100755
index 00000000..7a7b548e
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ThreadPool.h
@@ -0,0 +1,625 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_ThreadPool.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_ThreadPool
+#define PARCLibrary_parc_ThreadPool
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_LinkedList.h>
+#include <parc/concurrent/parc_Timeout.h>
+#include <parc/concurrent/parc_FutureTask.h>
+
+struct PARCThreadPool;
+typedef struct PARCThreadPool PARCThreadPool;
+
+/**
+ * Increase the number of references to a `PARCThreadPool` instance.
+ *
+ * Note that new `PARCThreadPool` is not created,
+ * only that the given `PARCThreadPool` reference count is incremented.
+ * Discard the reference by invoking `parcThreadPool_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * PARCThreadPool *b = parcThreadPool_Acquire();
+ *
+ * parcThreadPool_Release(&a);
+ * parcThreadPool_Release(&b);
+ * }
+ * @endcode
+ */
+PARCThreadPool *parcThreadPool_Acquire(const PARCThreadPool *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcThreadPool_OptionalAssertValid(_instance_)
+#else
+# define parcThreadPool_OptionalAssertValid(_instance_) parcThreadPool_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCThreadPool` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * parcThreadPool_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcThreadPool_Release(&b);
+ * }
+ * @endcode
+ */
+void parcThreadPool_AssertValid(const PARCThreadPool *instance);
+
+/**
+ * Create an instance of PARCThreadPool
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCThreadPool instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCThreadPool *parcThreadPool_Create(int poolSize);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ * @param [in] other A pointer to a valid PARCThreadPool instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ * PARCThreadPool *b = parcThreadPool_Create();
+ *
+ * if (parcThreadPool_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcThreadPool_Release(&a);
+ * parcThreadPool_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcThreadPool_Equals
+ */
+int parcThreadPool_Compare(const PARCThreadPool *instance, const PARCThreadPool *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCThreadPool instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCThreadPool` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * PARCThreadPool *copy = parcThreadPool_Copy(&b);
+ *
+ * parcThreadPool_Release(&b);
+ * parcThreadPool_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCThreadPool *parcThreadPool_Copy(const PARCThreadPool *original);
+
+/**
+ * Print a human readable representation of the given `PARCThreadPool`.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * parcThreadPool_Display(a, 0);
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcThreadPool_Display(const PARCThreadPool *instance, int indentation);
+
+/**
+ * Determine if two `PARCThreadPool` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCThreadPool` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcThreadPool_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcThreadPool_Equals(x, y)` must return true if and only if
+ * `parcThreadPool_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcThreadPool_Equals(x, y)` returns true and
+ * `parcThreadPool_Equals(y, z)` returns true,
+ * then `parcThreadPool_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcThreadPool_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcThreadPool_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCThreadPool instance.
+ * @param [in] y A pointer to a valid PARCThreadPool instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ * PARCThreadPool *b = parcThreadPool_Create();
+ *
+ * if (parcThreadPool_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcThreadPool_Release(&a);
+ * parcThreadPool_Release(&b);
+ * }
+ * @endcode
+ * @see parcThreadPool_HashCode
+ */
+bool parcThreadPool_Equals(const PARCThreadPool *x, const PARCThreadPool *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcThreadPool_Equals} method,
+ * then calling the {@link parcThreadPool_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcThreadPool_Equals} function,
+ * then calling the `parcThreadPool_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * PARCHashCode hashValue = parcThreadPool_HashCode(buffer);
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcThreadPool_HashCode(const PARCThreadPool *instance);
+
+/**
+ * Determine if an instance of `PARCThreadPool` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * if (parcThreadPool_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcThreadPool_IsValid(const PARCThreadPool *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCThreadPool` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcThreadPool_Release(PARCThreadPool **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * PARCJSON *json = parcThreadPool_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcThreadPool_ToJSON(const PARCThreadPool *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCThreadPool`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * char *string = parcThreadPool_ToString(a);
+ *
+ * parcThreadPool_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcThreadPool_Display
+ */
+char *parcThreadPool_ToString(const PARCThreadPool *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcThreadPool_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCThreadPool instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcThreadPool_Lock(object)) {
+ * parcThreadPool_Notify(object);
+ * parcThreadPool_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcThreadPool, PARCThreadPool);
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcThreadPool_Wait`, `parcThreadPool_WaitFor`, `parcThreadPool_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcThreadPool_Lock(object)) {
+ * parcThreadPool_NotifyAll(object);
+ * parcThreadPool_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotifyAll(parcThreadPool, PARCThreadPool);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcThreadPool_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcThreadPool_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcThreadPool, PARCThreadPool);
+
+/**
+ * Obtain the lock on the given `PARCThreadPool` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCThreadPool` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcThreadPool_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcThreadPool, PARCThreadPool);
+
+/**
+ * Try to obtain the advisory lock on the given PARCThreadPool instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCThreadPool instance.
+ *
+ * @return true The PARCThreadPool is locked.
+ * @return false The PARCThreadPool is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcThreadPool_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcThreadPool, PARCThreadPool);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCThreadPool` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * @return true The `PARCThreadPool` was locked and now is unlocked.
+ * @return false The `PARCThreadPool` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcThreadPool_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcThreadPool, PARCThreadPool);
+
+/**
+ * Determine if the advisory lock on the given `PARCThreadPool` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * @return true The `PARCThreadPool` is locked.
+ * @return false The `PARCThreadPool` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcThreadPool_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcThreadPool, PARCThreadPool);
+
+/**
+ * Sets the policy governing whether core threads may time out and terminate if no tasks arrive within the keep-alive time, being replaced if needed when new tasks arrive.
+ */
+void parcThreadPool_SetAllowCoreThreadTimeOut(PARCThreadPool *pool, bool value);
+
+/**
+ * Returns true if this pool allows core threads to time out and terminate if no tasks arrive within the keepAlive time, being replaced if needed when new tasks arrive.
+ */
+bool parcThreadPool_GetAllowsCoreThreadTimeOut(const PARCThreadPool *pool);
+
+/**
+ * Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, whichever happens first.
+ */
+bool parcThreadPool_AwaitTermination(PARCThreadPool *pool, PARCTimeout *timeout);
+
+/**
+ * Executes the given task sometime in the future.
+ */
+bool parcThreadPool_Execute(PARCThreadPool *pool, PARCFutureTask *task);
+
+/**
+ * Returns the approximate number of threads that are actively executing tasks.
+ */
+int parcThreadPool_GetActiveCount(const PARCThreadPool *pool);
+
+/**
+ * Returns the approximate total number of tasks that have completed execution.
+ */
+uint64_t parcThreadPool_GetCompletedTaskCount(const PARCThreadPool *pool);
+
+/**
+ * Returns the core number of threads.
+ */
+int parcThreadPool_GetCorePoolSize(const PARCThreadPool *pool);
+
+/**
+ * Returns the thread keep-alive time, which is the amount of time that threads in excess of the core pool size may remain idle before being terminated.
+ */
+PARCTimeout *parcThreadPool_GetKeepAliveTime(const PARCThreadPool *pool);
+
+/**
+ * Returns the largest number of threads that have ever simultaneously been in the pool.
+ */
+int parcThreadPool_GetLargestPoolSize(const PARCThreadPool *pool);
+
+/**
+ * Returns the maximum allowed number of threads.
+ */
+int parcThreadPool_GetMaximumPoolSize(const PARCThreadPool *pool);
+
+/**
+ * Returns the current number of threads in the pool.
+ */
+int parcThreadPool_GetPoolSize(const PARCThreadPool *pool);
+
+/**
+ * Returns the task queue used by this executor.
+ */
+PARCLinkedList *parcThreadPool_GetQueue(const PARCThreadPool *pool);
+
+/**
+ * Returns the approximate total number of tasks that have ever been scheduled for execution.
+ */
+long parcThreadPool_GetTaskCount(const PARCThreadPool *pool);
+
+/**
+ * Returns true if this executor has been shut down.
+ */
+bool parcThreadPool_IsShutdown(const PARCThreadPool *pool);
+
+/**
+ * Returns true if all tasks have completed following shut down.
+ */
+bool parcThreadPool_IsTerminated(const PARCThreadPool *pool);
+
+/**
+ * Returns true if this executor is in the process of terminating after shutdown() or shutdownNow() but has not completely terminated.
+ */
+bool parcThreadPool_IsTerminating(const PARCThreadPool *pool);
+
+/**
+ * Starts all core threads, causing them to idly wait for work.
+ */
+int parcThreadPool_PrestartAllCoreThreads(PARCThreadPool *pool);
+
+/**
+ * Starts a core thread, causing it to idly wait for work.
+ */
+bool parcThreadPool_PrestartCoreThread(PARCThreadPool *pool);
+
+/**
+ * Tries to remove from the work queue all Future tasks that have been cancelled.
+ */
+void parcThreadPool_Purge(PARCThreadPool *pool);
+
+/**
+ * Removes this task from the executor's internal queue if it is present, thus causing it not to be run if it has not already started.
+ */
+bool parcThreadPool_Remove(PARCThreadPool *pool, PARCFutureTask *task);
+
+/**
+ * Sets the core number of threads.
+ */
+void parcThreadPool_SetCorePoolSize(PARCThreadPool *pool, int corePoolSize);
+
+/**
+ * Sets the time limit for which threads may remain idle before being terminated.
+ */
+void parcThreadPool_SetKeepAliveTime(PARCThreadPool *pool, PARCTimeout *timeout);
+
+/**
+ * Sets the maximum allowed number of threads.
+ */
+void parcThreadPool_SetMaximumPoolSize(PARCThreadPool *pool, int maximumPoolSize);
+
+/**
+ * Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
+ */
+void parcThreadPool_Shutdown(PARCThreadPool *pool);
+
+/**
+ * Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
+ */
+PARCLinkedList *parcThreadPool_ShutdownNow(PARCThreadPool *pool);
+#endif
diff --git a/libparc/parc/concurrent/parc_Timeout.c b/libparc/parc/concurrent/parc_Timeout.c
new file mode 100755
index 00000000..4ea03977
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Timeout.c
@@ -0,0 +1,25 @@
+/*
+ * 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 <parc/concurrent/parc_Timeout.h>
+
+
+bool
+parcTimeout_Equals(PARCTimeout x, PARCTimeout y)
+{
+ return x == y;
+}
diff --git a/libparc/parc/concurrent/parc_Timeout.h b/libparc/parc/concurrent/parc_Timeout.h
new file mode 100644
index 00000000..9edc24a0
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Timeout.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup threading
+ *
+ */
+#ifndef parc_Timeout_h
+#define parc_Timeout_h
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef uint64_t PARCTimeout;
+
+/**
+ * @def PARCTimeout_Never
+ * This represents a timeout that will never happen.
+ */
+#define PARCTimeout_Never NULL
+
+/*
+ * @def PARCTimeout_Immediate
+ * This represents a timeout that immediately happens.
+ * Equivalent to parcTimeout_NanoSeconds(0)
+ */
+#define PARCTimeout_Immediate (&(PARCTimeout) { 0 })
+
+/*
+ * @def PARCTimeout_NanoSeconds
+ * This represents a timeout that will occur in the specified number of nanoseconds.
+ */
+#define parcTimeout_NanoSeconds(_nsec_) (&(PARCTimeout) { _nsec_ })
+
+/*
+ * @def PARCTimeout_MicroSeconds
+ * This represents a timeout that will occur in the specified number of microseconds.
+ */
+#define parcTimeout_MicroSeconds(_usec_) parcTimeout_NanoSeconds(_usec_ * 1000)
+
+/*
+ * @def PARCTimeout_MilliSeconds
+ * This represents a timeout that will occur in the specified number of microseconds.
+ */
+#define parcTimeout_MilliSeconds(_msec_) parcTimeout_MicroSeconds(_msec_ * 1000)
+
+/**
+ * Determine if two `PARCTimeout` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCTimeout` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcTimeout_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcTimeout_Equals(x, y)` must return true if and only if
+ * `parcTimeout_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcTimeout_Equals(x, y)` returns true and
+ * `parcTimeout_Equals(y, z)` returns true,
+ * then `parcTimeout_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcTimeout_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcTimeout_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A valid PARCTimeout instance.
+ * @param [in] y A valid PARCTimeout instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimeout *a = parcTimeout_Create();
+ * PARCTimeout *b = parcTimeout_Create();
+ *
+ * if (parcTimeout_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcTimeout_Release(&a);
+ * parcTimeout_Release(&b);
+ * }
+ * @endcode
+ * @see parcTimeout_HashCode
+ */
+bool parcTimeout_Equals(PARCTimeout x, PARCTimeout y);
+
+/**
+ * Predicate function returning true if the given timeout represents an infinite delay.
+ *
+ * @param [in] timeout A pointer to a valid PARCTimeout value.
+ *
+ * @return true The given timeout represents an infinite delay.
+ */
+static inline bool
+parcTimeout_IsNever(const PARCTimeout *timeout)
+{
+ return (timeout == PARCTimeout_Never);
+}
+
+/**
+ * Predicate function returning true if the given timeout represents an immediate, no-delay timeout.
+ *
+ * @param [in] timeout A pointer to a valid PARCTimeout value.
+ *
+ * @return true The given timeout represents an immediate, no-delay timeout.
+ */
+static inline bool
+parcTimeout_IsImmediate(const PARCTimeout *timeout)
+{
+ return parcTimeout_IsNever(timeout) ? false : (*timeout == 0);
+}
+
+/**
+ * Return the number of nano-seconds in the given PARCTimeout instance.
+ *
+ * If the PARCTimeout is never (`parcTimeout_IsNever` returns `true`), the returned value is UINT64_MAX.
+ *
+ * @param [in] timeout A pointer to a valid PARCTimeout value.
+ *
+ * @return The number of nano-seconds in the given PARCTimeout instance, UINT64_MAX.
+ */
+static inline uint64_t
+parcTimeout_InNanoSeconds(const PARCTimeout *timeout)
+{
+ return parcTimeout_IsNever(timeout) ? UINT64_MAX : *timeout;
+}
+#endif /* parc_Timeout_h */
diff --git a/libparc/parc/concurrent/parc_Timer.c b/libparc/parc/concurrent/parc_Timer.c
new file mode 100755
index 00000000..e6d84de4
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Timer.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include "parc_Timer.h"
+
+struct PARCTimer {
+ int delay;
+};
+
+static void
+_parcTimer_Finalize(PARCTimer **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCTimer pointer.");
+
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcTimer, PARCTimer);
+
+parcObject_ImplementRelease(parcTimer, PARCTimer);
+
+parcObject_ExtendPARCObject(PARCTimer, _parcTimer_Finalize, parcTimer_Copy, parcTimer_ToString, parcTimer_Equals, parcTimer_Compare, parcTimer_HashCode, parcTimer_ToJSON);
+
+
+void
+parcTimer_AssertValid(const PARCTimer *instance)
+{
+ assertTrue(parcTimer_IsValid(instance),
+ "PARCTimer is not valid.");
+}
+
+PARCTimer *
+parcTimer_Create(void)
+{
+ PARCTimer *result = parcObject_CreateInstance(PARCTimer);
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+int
+parcTimer_Compare(const PARCTimer *instance, const PARCTimer *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCTimer *
+parcTimer_Copy(const PARCTimer *original)
+{
+ PARCTimer *result = parcTimer_Create();
+
+ return result;
+}
+
+void
+parcTimer_Display(const PARCTimer *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCTimer@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcTimer_Equals(const PARCTimer *x, const PARCTimer *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ return true;
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcTimer_HashCode(const PARCTimer *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcTimer_IsValid(const PARCTimer *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcTimer_ToJSON(const PARCTimer *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcTimer_ToString(const PARCTimer *instance)
+{
+ char *result = parcMemory_Format("PARCTimer@%p\n", instance);
+
+ return result;
+}
+
+void
+parcTimer_Cancel(PARCTimer *timer)
+{
+}
+
+int
+parcTimer_Purge(PARCTimer *timer)
+{
+ return 0;
+}
+
+void
+parcTimer_ScheduleAtTime(PARCTimer *timer, PARCFutureTask *task, time_t absoluteTime)
+{
+}
+
+void
+parcTimer_ScheduleAtTimeAndRepeat(PARCTimer *timer, PARCFutureTask *task, time_t firstTime, long period)
+{
+}
+
+void
+parcTimer_ScheduleAfterDelay(PARCTimer *timer, PARCFutureTask *task, long delay)
+{
+}
+
+void
+parcTimer_ScheduleAfterDelayAndRepeat(PARCTimer *timer, PARCFutureTask *task, long delay, long period)
+{
+}
+
diff --git a/libparc/parc/concurrent/parc_Timer.h b/libparc/parc/concurrent/parc_Timer.h
new file mode 100755
index 00000000..416bfba4
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Timer.h
@@ -0,0 +1,431 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file parc_Timer.h
+ * @ingroup threading
+ * @brief A facility for threads to schedule tasks for future execution in a background thread.
+ *
+ * Tasks may be scheduled for one-time execution, or for repeated execution at regular intervals.
+ *
+ * Corresponding to each Timer object is a single background thread that is used to execute all of the timer's tasks,
+ * sequentially. Timer tasks should complete quickly.
+ * If a timer task takes excessive time to complete, it "hogs" the timer's task execution thread.
+ * This can, in turn, delay the execution of subsequent tasks,
+ * which may "bunch up" and execute in rapid succession when (and if) the offending task finally completes.
+ *
+ * After the last live reference to a Timer object goes away and all outstanding tasks have completed execution,
+ * the timer's task execution thread terminates gracefully (and becomes subject to garbage collection).
+ * However, this can take arbitrarily long to occur.
+ * By default, the task execution thread does not run as a daemon thread,
+ * so it is capable of keeping an application from terminating.
+ * If a caller wants to terminate a timer's task execution thread rapidly, the caller should invoke the timer's cancel method.
+ *
+ * If the timer's task execution thread terminates unexpectedly,
+ * for example, because its stop method is invoked,
+ * any further attempt to schedule a task on the timer will result in an IllegalStateException,
+ * as if the timer's cancel method had been invoked.
+ *
+ * This class is thread-safe: multiple threads can share a single Timer object without the need for external synchronization.
+ *
+ * This class does not offer real-time guarantees: it schedules tasks using the Object.wait(long) method.
+ *
+ */
+#ifndef PARCLibrary_parc_Timer
+#define PARCLibrary_parc_Timer
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/concurrent/parc_FutureTask.h>
+
+struct PARCTimer;
+typedef struct PARCTimer PARCTimer;
+
+/**
+ * Increase the number of references to a `PARCTimer` instance.
+ *
+ * Note that new `PARCTimer` is not created,
+ * only that the given `PARCTimer` reference count is incremented.
+ * Discard the reference by invoking `parcTimer_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * PARCTimer *b = parcTimer_Acquire();
+ *
+ * parcTimer_Release(&a);
+ * parcTimer_Release(&b);
+ * }
+ * @endcode
+ */
+PARCTimer *parcTimer_Acquire(const PARCTimer *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcTimer_OptionalAssertValid(_instance_)
+#else
+# define parcTimer_OptionalAssertValid(_instance_) parcTimer_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCTimer` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * parcTimer_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcTimer_Release(&b);
+ * }
+ * @endcode
+ */
+void parcTimer_AssertValid(const PARCTimer *instance);
+
+/**
+ * Create an instance of PARCTimer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCTimer instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+PARCTimer *parcTimer_Create(void);
+
+/**
+ * Compares @p instance with @p other for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as @p instance
+ * is less than, equal to, or greater than @p other.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ * @param [in] other A pointer to a valid PARCTimer instance.
+ *
+ * @return <0 Instance is less than @p other.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ * PARCTimer *b = parcTimer_Create();
+ *
+ * if (parcTimer_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcTimer_Release(&a);
+ * parcTimer_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcTimer_Equals
+ */
+int parcTimer_Compare(const PARCTimer *instance, const PARCTimer *other);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A pointer to a valid PARCTimer instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCTimer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * PARCTimer *copy = parcTimer_Copy(&b);
+ *
+ * parcTimer_Release(&b);
+ * parcTimer_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCTimer *parcTimer_Copy(const PARCTimer *original);
+
+/**
+ * Print a human readable representation of the given `PARCTimer`.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * parcTimer_Display(a, 0);
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+void parcTimer_Display(const PARCTimer *instance, int indentation);
+
+/**
+ * Determine if two `PARCTimer` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCTimer` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcTimer_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcTimer_Equals(x, y)` must return true if and only if
+ * `parcTimer_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcTimer_Equals(x, y)` returns true and
+ * `parcTimer_Equals(y, z)` returns true,
+ * then `parcTimer_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcTimer_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcTimer_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCTimer instance.
+ * @param [in] y A pointer to a valid PARCTimer instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ * PARCTimer *b = parcTimer_Create();
+ *
+ * if (parcTimer_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcTimer_Release(&a);
+ * parcTimer_Release(&b);
+ * }
+ * @endcode
+ * @see parcTimer_HashCode
+ */
+bool parcTimer_Equals(const PARCTimer *x, const PARCTimer *y);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an execution of an application,
+ * the `HashCode` function must consistently return the same value,
+ * provided no information used in a corresponding comparisons on the instance is modified.
+ *
+ * This value need not remain consistent from one execution of an application to another execution of the same application.
+ * If two instances are equal according to the {@link parcTimer_Equals} method,
+ * then calling the {@link parcTimer_HashCode} method on each of the two instances must produce the same integer result.
+ *
+ * It is not required that if two instances are unequal according to the
+ * {@link parcTimer_Equals} function,
+ * then calling the `parcTimer_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * PARCHashCode hashValue = parcTimer_HashCode(buffer);
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcTimer_HashCode(const PARCTimer *instance);
+
+/**
+ * Determine if an instance of `PARCTimer` is valid.
+ *
+ * Valid means the internal state of the type is consistent with its required current or future behaviour.
+ * This may include the validation of internal instances of types.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * if (parcTimer_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcTimer_IsValid(const PARCTimer *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCTimer` instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+void parcTimer_Release(PARCTimer **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * @return NULL Memory could not be allocated to contain the `PARCJSON` instance.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * PARCJSON *json = parcTimer_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcTimer_ToJSON(const PARCTimer *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCTimer`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * char *string = parcTimer_ToString(a);
+ *
+ * parcTimer_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcTimer_Display
+ */
+char *parcTimer_ToString(const PARCTimer *timer);
+
+/**
+ * Terminates this timer, discarding any currently scheduled tasks.
+ *
+ * Does not interfere with a currently executing task (if it exists).
+ * Once a timer has been terminated, its execution thread terminates gracefully,
+ * and no more tasks may be scheduled on it.
+ *
+ * Note that calling this method from within the run method of a timer task that was invoked
+ * by this timer absolutely guarantees that the ongoing task execution is the last task execution
+ * that will ever be performed by this timer.
+ *
+ * This method may be called repeatedly; the second and subsequent calls have no effect.
+ */
+void parcTimer_Cancel(PARCTimer *timer);
+
+/**
+ * Removes all cancelled tasks from this timer's task queue.
+ *
+ * Calling this method has no effect on the behavior of the timer,
+ * but eliminates the references to the cancelled tasks from the queue.
+ * If there are no external references to these tasks, they become eligible for garbage collection.
+ *
+ * Most programs will have no need to call this method.
+ * It is designed for use by the rare application that cancels a large number of tasks.
+ * Calling this method trades time for space: the runtime of the method may be proportional to
+ * n + c log n, where n is the number of tasks in the queue and c is the number of cancelled tasks.
+ *
+ * It is permissible to call this method from within a task scheduled on this timer.
+ *
+ * @returns the number of tasks removed from the queue.
+ */
+int parcTimer_Purge(PARCTimer *timer);
+
+/**
+ * Schedules the specified task for execution at the specified time.
+ */
+void parcTimer_ScheduleAtTime(PARCTimer *timer, PARCFutureTask *task, time_t absoluteTime);
+
+/**
+ * Schedules the specified task for repeated fixed-delay execution, beginning at the specified time.
+ */
+void parcTimer_ScheduleAtTimeAndRepeat(PARCTimer *timer, PARCFutureTask *task, time_t firstTime, long period);
+
+/**
+ * Schedules the specified task for execution after the specified delay.
+ */
+void parcTimer_ScheduleAfterDelay(PARCTimer *timer, PARCFutureTask *task, long delay);
+
+/**
+ * Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay.
+ */
+void parcTimer_ScheduleAfterDelayAndRepeat(PARCTimer *timer, PARCFutureTask *task, long delay, long period);
+#endif
diff --git a/libparc/parc/concurrent/test/.gitignore b/libparc/parc/concurrent/test/.gitignore
new file mode 100644
index 00000000..2c9fe4f5
--- /dev/null
+++ b/libparc/parc/concurrent/test/.gitignore
@@ -0,0 +1,10 @@
+test_parc_Notifier
+test_parc_RingBuffer_1x1
+test_parc_RingBuffer_NxM
+test_parc_AtomicUint64
+test_parc_Barrier
+test_parc_AtomicUint16
+test_parc_AtomicUint32
+test_parc_AtomicUint8
+test_parc_Synchronizer
+test_parc_Lock
diff --git a/libparc/parc/concurrent/test/CMakeLists.txt b/libparc/parc/concurrent/test/CMakeLists.txt
new file mode 100644
index 00000000..092d0202
--- /dev/null
+++ b/libparc/parc/concurrent/test/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(TestsExpectedToPass
+ test_parc_AtomicUint16
+ test_parc_AtomicUint32
+ test_parc_AtomicUint64
+ test_parc_AtomicUint8
+ test_parc_FutureTask
+ test_parc_Lock
+ test_parc_Notifier
+ test_parc_RingBuffer_1x1
+ test_parc_RingBuffer_NxM
+ test_parc_ScheduledTask
+ test_parc_ScheduledThreadPool
+ test_parc_Synchronizer
+ test_parc_Thread
+ test_parc_ThreadPool
+ test_parc_Timer
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libparc/parc/concurrent/test/test_parc_AtomicUint16.c b/libparc/parc/concurrent/test/test_parc_AtomicUint16.c
new file mode 100644
index 00000000..ed97cc95
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_AtomicUint16.c
@@ -0,0 +1,361 @@
+/*
+ * 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 "../parc_AtomicUint16.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_AtomicUint16)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Macros);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_AtomicUint16)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_AtomicUint16)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ assertNotNull(instance, "Expeced non-null result from parcAtomicUint16_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcAtomicUint16_Acquire, instance);
+
+ parcAtomicUint16_Release(&instance);
+ assertNull(instance, "Expected null result from parcAtomicUint16_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_Compare)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *high = parcAtomicUint16_Create(8);
+ PARCAtomicUint16 *low = parcAtomicUint16_Create(6);
+ PARCAtomicUint16 *equal = parcAtomicUint16_Create(7);
+
+ int actual = parcAtomicUint16_Compare(instance, high);
+ assertTrue(actual < 0, "Expected < 0");
+ actual = parcAtomicUint16_Compare(instance, low);
+ assertTrue(actual > 0, "Expected > 0");
+ actual = parcAtomicUint16_Compare(instance, equal);
+ assertTrue(actual == 0, "Expected == 0");
+
+ parcAtomicUint16_Release(&instance);
+ parcAtomicUint16_Release(&high);
+ parcAtomicUint16_Release(&low);
+ parcAtomicUint16_Release(&equal);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_Copy)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *copy = parcAtomicUint16_Copy(instance);
+
+ assertTrue(parcAtomicUint16_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcAtomicUint16_Release(&instance);
+ parcAtomicUint16_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_Equals)
+{
+ PARCAtomicUint16 *x = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *y = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *z = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *u1 = parcAtomicUint16_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcAtomicUint16_Release(&x);
+ parcAtomicUint16_Release(&y);
+ parcAtomicUint16_Release(&z);
+ parcAtomicUint16_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_HashCode)
+{
+ PARCAtomicUint16 *x = parcAtomicUint16_Create(7);
+ parcAtomicUint16_HashCode(x);
+ parcAtomicUint16_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_IsValid)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ assertTrue(parcAtomicUint16_IsValid(instance), "Expected parcAtomicUint16_Create to result in a valid instance.");
+
+ parcAtomicUint16_Release(&instance);
+ assertFalse(parcAtomicUint16_IsValid(instance), "Expected parcAtomicUint16_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_SubtractImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ parcAtomicUint16_SubtractImpl(instance, 1);
+
+ uint16_t actual = parcAtomicUint16_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu16, actual);
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_AddImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ parcAtomicUint16_AddImpl(instance, 1);
+
+ uint16_t actual = parcAtomicUint16_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu16, actual);
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_CompareAndSwapImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ bool actual = parcAtomicUint16_CompareAndSwapImpl(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint16_CompareAndSwapImpl to return true");
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Macros)
+{
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint16_Subtract);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint16_Add);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint16_CompareAndSwap);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Macros)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Macros)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint16_Subtract)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ parcAtomicUint16_Subtract(instance, 1);
+
+ uint16_t actual = parcAtomicUint16_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu16, actual);
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint16_Add)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ parcAtomicUint16_Add(instance, 1);
+
+ uint16_t actual = parcAtomicUint16_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu16, actual);
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint16_CompareAndSwap)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ bool actual = parcAtomicUint16_CompareAndSwap(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint16_CompareAndSwap to return true");
+ parcAtomicUint16_Release(&instance);
+}
+
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_Subtract_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_Add_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_CompareAndSwap_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_Subtract_MACRO)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(65535);
+
+ while (parcAtomicUint16_Subtract(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_Add_MACRO)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(1);
+
+ while (parcAtomicUint16_Add(instance, 1) < 65535) {
+ ;
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_CompareAndSwap_MACRO)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(0);
+
+ for (uint16_t i = 0; i < 65535; i++) {
+ bool actual = parcAtomicUint16_CompareAndSwap(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint16_CompareAndSwap to return true");
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_SubtractImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(65535);
+
+ while (parcAtomicUint16_SubtractImpl(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_AddImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(1);
+
+ while (parcAtomicUint16_AddImpl(instance, 1) < 65535) {
+ ;
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_CompareAndSwapImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(0);
+
+ for (uint16_t i = 0; i < 65535; i++) {
+ bool actual = parcAtomicUint16_CompareAndSwapImpl(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint16_CompareAndSwapImpl to return true");
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_AtomicUint16);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_AtomicUint32.c b/libparc/parc/concurrent/test/test_parc_AtomicUint32.c
new file mode 100644
index 00000000..1649cf1c
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_AtomicUint32.c
@@ -0,0 +1,361 @@
+/*
+ * 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 "../parc_AtomicUint64.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_AtomicUint64)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Macros);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_AtomicUint64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_AtomicUint64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ assertNotNull(instance, "Expeced non-null result from parcAtomicUint64_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcAtomicUint64_Acquire, instance);
+
+ parcAtomicUint64_Release(&instance);
+ assertNull(instance, "Expected null result from parcAtomicUint64_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Compare)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *high = parcAtomicUint64_Create(8);
+ PARCAtomicUint64 *low = parcAtomicUint64_Create(6);
+ PARCAtomicUint64 *equal = parcAtomicUint64_Create(7);
+
+ int actual = parcAtomicUint64_Compare(instance, high);
+ assertTrue(actual < 0, "Expected < 0");
+ actual = parcAtomicUint64_Compare(instance, low);
+ assertTrue(actual > 0, "Expected > 0");
+ actual = parcAtomicUint64_Compare(instance, equal);
+ assertTrue(actual == 0, "Expected == 0");
+
+ parcAtomicUint64_Release(&instance);
+ parcAtomicUint64_Release(&high);
+ parcAtomicUint64_Release(&low);
+ parcAtomicUint64_Release(&equal);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Copy)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *copy = parcAtomicUint64_Copy(instance);
+
+ assertTrue(parcAtomicUint64_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcAtomicUint64_Release(&instance);
+ parcAtomicUint64_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Equals)
+{
+ PARCAtomicUint64 *x = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *y = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *z = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *u1 = parcAtomicUint64_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcAtomicUint64_Release(&x);
+ parcAtomicUint64_Release(&y);
+ parcAtomicUint64_Release(&z);
+ parcAtomicUint64_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_HashCode)
+{
+ PARCAtomicUint64 *x = parcAtomicUint64_Create(7);
+ parcAtomicUint64_HashCode(x);
+ parcAtomicUint64_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_IsValid)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ assertTrue(parcAtomicUint64_IsValid(instance), "Expected parcAtomicUint64_Create to result in a valid instance.");
+
+ parcAtomicUint64_Release(&instance);
+ assertFalse(parcAtomicUint64_IsValid(instance), "Expected parcAtomicUint64_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_SubtractImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_SubtractImpl(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_AddImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_AddImpl(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_CompareAndSwapImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ bool actual = parcAtomicUint64_CompareAndSwapImpl(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwapImpl to return true");
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Macros)
+{
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_Subtract);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_Add);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_CompareAndSwap);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Macros)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Macros)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_Subtract)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_Subtract(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_Add)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_Add(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_CompareAndSwap)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ bool actual = parcAtomicUint64_CompareAndSwap(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwap to return true");
+ parcAtomicUint64_Release(&instance);
+}
+
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_Subtract_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_Add_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwap_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_Subtract_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(100000000);
+
+ while (parcAtomicUint64_Subtract(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_Add_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(1);
+
+ while (parcAtomicUint64_Add(instance, 1) < 100000000) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwap_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(0);
+
+ for (uint64_t i = 0; i < 100000000; i++) {
+ bool actual = parcAtomicUint64_CompareAndSwap(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwap to return true");
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_SubtractImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(100000000);
+
+ while (parcAtomicUint64_SubtractImpl(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_AddImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(1);
+
+ while (parcAtomicUint64_AddImpl(instance, 1) < 100000000) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwapImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(0);
+
+ for (uint64_t i = 0; i < 100000000; i++) {
+ bool actual = parcAtomicUint64_CompareAndSwapImpl(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwapImpl to return true");
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_AtomicUint64);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_AtomicUint64.c b/libparc/parc/concurrent/test/test_parc_AtomicUint64.c
new file mode 100644
index 00000000..1649cf1c
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_AtomicUint64.c
@@ -0,0 +1,361 @@
+/*
+ * 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 "../parc_AtomicUint64.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_AtomicUint64)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Macros);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_AtomicUint64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_AtomicUint64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ assertNotNull(instance, "Expeced non-null result from parcAtomicUint64_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcAtomicUint64_Acquire, instance);
+
+ parcAtomicUint64_Release(&instance);
+ assertNull(instance, "Expected null result from parcAtomicUint64_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Compare)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *high = parcAtomicUint64_Create(8);
+ PARCAtomicUint64 *low = parcAtomicUint64_Create(6);
+ PARCAtomicUint64 *equal = parcAtomicUint64_Create(7);
+
+ int actual = parcAtomicUint64_Compare(instance, high);
+ assertTrue(actual < 0, "Expected < 0");
+ actual = parcAtomicUint64_Compare(instance, low);
+ assertTrue(actual > 0, "Expected > 0");
+ actual = parcAtomicUint64_Compare(instance, equal);
+ assertTrue(actual == 0, "Expected == 0");
+
+ parcAtomicUint64_Release(&instance);
+ parcAtomicUint64_Release(&high);
+ parcAtomicUint64_Release(&low);
+ parcAtomicUint64_Release(&equal);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Copy)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *copy = parcAtomicUint64_Copy(instance);
+
+ assertTrue(parcAtomicUint64_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcAtomicUint64_Release(&instance);
+ parcAtomicUint64_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Equals)
+{
+ PARCAtomicUint64 *x = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *y = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *z = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *u1 = parcAtomicUint64_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcAtomicUint64_Release(&x);
+ parcAtomicUint64_Release(&y);
+ parcAtomicUint64_Release(&z);
+ parcAtomicUint64_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_HashCode)
+{
+ PARCAtomicUint64 *x = parcAtomicUint64_Create(7);
+ parcAtomicUint64_HashCode(x);
+ parcAtomicUint64_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_IsValid)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ assertTrue(parcAtomicUint64_IsValid(instance), "Expected parcAtomicUint64_Create to result in a valid instance.");
+
+ parcAtomicUint64_Release(&instance);
+ assertFalse(parcAtomicUint64_IsValid(instance), "Expected parcAtomicUint64_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_SubtractImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_SubtractImpl(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_AddImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_AddImpl(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_CompareAndSwapImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ bool actual = parcAtomicUint64_CompareAndSwapImpl(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwapImpl to return true");
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Macros)
+{
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_Subtract);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_Add);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_CompareAndSwap);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Macros)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Macros)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_Subtract)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_Subtract(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_Add)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_Add(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_CompareAndSwap)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ bool actual = parcAtomicUint64_CompareAndSwap(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwap to return true");
+ parcAtomicUint64_Release(&instance);
+}
+
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_Subtract_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_Add_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwap_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_Subtract_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(100000000);
+
+ while (parcAtomicUint64_Subtract(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_Add_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(1);
+
+ while (parcAtomicUint64_Add(instance, 1) < 100000000) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwap_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(0);
+
+ for (uint64_t i = 0; i < 100000000; i++) {
+ bool actual = parcAtomicUint64_CompareAndSwap(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwap to return true");
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_SubtractImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(100000000);
+
+ while (parcAtomicUint64_SubtractImpl(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_AddImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(1);
+
+ while (parcAtomicUint64_AddImpl(instance, 1) < 100000000) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwapImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(0);
+
+ for (uint64_t i = 0; i < 100000000; i++) {
+ bool actual = parcAtomicUint64_CompareAndSwapImpl(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwapImpl to return true");
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_AtomicUint64);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_AtomicUint8.c b/libparc/parc/concurrent/test/test_parc_AtomicUint8.c
new file mode 100644
index 00000000..5b89d052
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_AtomicUint8.c
@@ -0,0 +1,361 @@
+/*
+ * 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 "../parc_AtomicUint8.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_AtomicUint8)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Macros);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_AtomicUint8)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_AtomicUint8)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ assertNotNull(instance, "Expeced non-null result from parcAtomicUint8_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcAtomicUint8_Acquire, instance);
+
+ parcAtomicUint8_Release(&instance);
+ assertNull(instance, "Expected null result from parcAtomicUint8_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_Compare)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *high = parcAtomicUint8_Create(8);
+ PARCAtomicUint8 *low = parcAtomicUint8_Create(6);
+ PARCAtomicUint8 *equal = parcAtomicUint8_Create(7);
+
+ int actual = parcAtomicUint8_Compare(instance, high);
+ assertTrue(actual < 0, "Expected < 0");
+ actual = parcAtomicUint8_Compare(instance, low);
+ assertTrue(actual > 0, "Expected > 0");
+ actual = parcAtomicUint8_Compare(instance, equal);
+ assertTrue(actual == 0, "Expected == 0");
+
+ parcAtomicUint8_Release(&instance);
+ parcAtomicUint8_Release(&high);
+ parcAtomicUint8_Release(&low);
+ parcAtomicUint8_Release(&equal);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_Copy)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *copy = parcAtomicUint8_Copy(instance);
+
+ assertTrue(parcAtomicUint8_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcAtomicUint8_Release(&instance);
+ parcAtomicUint8_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_Equals)
+{
+ PARCAtomicUint8 *x = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *y = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *z = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *u1 = parcAtomicUint8_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcAtomicUint8_Release(&x);
+ parcAtomicUint8_Release(&y);
+ parcAtomicUint8_Release(&z);
+ parcAtomicUint8_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_HashCode)
+{
+ PARCAtomicUint8 *x = parcAtomicUint8_Create(7);
+ parcAtomicUint8_HashCode(x);
+ parcAtomicUint8_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_IsValid)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ assertTrue(parcAtomicUint8_IsValid(instance), "Expected parcAtomicUint8_Create to result in a valid instance.");
+
+ parcAtomicUint8_Release(&instance);
+ assertFalse(parcAtomicUint8_IsValid(instance), "Expected parcAtomicUint8_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_SubtractImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ parcAtomicUint8_SubtractImpl(instance, 1);
+
+ uint8_t actual = parcAtomicUint8_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu8, actual);
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_AddImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ parcAtomicUint8_AddImpl(instance, 1);
+
+ uint8_t actual = parcAtomicUint8_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu8, actual);
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_CompareAndSwapImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ bool actual = parcAtomicUint8_CompareAndSwapImpl(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint8_CompareAndSwapImpl to return true");
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Macros)
+{
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint8_Subtract);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint8_Add);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint8_CompareAndSwap);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Macros)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Macros)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint8_Subtract)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ parcAtomicUint8_Subtract(instance, 1);
+
+ uint8_t actual = parcAtomicUint8_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu8, actual);
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint8_Add)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ parcAtomicUint8_Add(instance, 1);
+
+ uint8_t actual = parcAtomicUint8_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu8, actual);
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint8_CompareAndSwap)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ bool actual = parcAtomicUint8_CompareAndSwap(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint8_CompareAndSwap to return true");
+ parcAtomicUint8_Release(&instance);
+}
+
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_Subtract_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_Add_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_CompareAndSwap_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_Subtract_MACRO)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(255);
+
+ while (parcAtomicUint8_Subtract(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_Add_MACRO)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(1);
+
+ while (parcAtomicUint8_Add(instance, 1) < 255) {
+ ;
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_CompareAndSwap_MACRO)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(0);
+
+ for (uint8_t i = 0; i < 255; i++) {
+ bool actual = parcAtomicUint8_CompareAndSwap(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint8_CompareAndSwap to return true");
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_SubtractImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(255);
+
+ while (parcAtomicUint8_SubtractImpl(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_AddImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(1);
+
+ while (parcAtomicUint8_AddImpl(instance, 1) < 255) {
+ ;
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_CompareAndSwapImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(0);
+
+ for (uint8_t i = 0; i < 255; i++) {
+ bool actual = parcAtomicUint8_CompareAndSwapImpl(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint8_CompareAndSwapImpl to return true");
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_AtomicUint8);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_FutureTask.c b/libparc/parc/concurrent/test/test_parc_FutureTask.c
new file mode 100644
index 00000000..c30d2cae
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_FutureTask.c
@@ -0,0 +1,317 @@
+/*
+ * 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 "../parc_FutureTask.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_FutureTask)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_FutureTask)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_FutureTask)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease_PARCObject);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void *
+_function(PARCFutureTask *task, void *parameter)
+{
+ return parameter;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+ assertNotNull(instance, "Expected non-null result from parcFutureTask_Create(_function, _function);");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcFutureTask_Acquire, instance);
+
+ parcFutureTask_Release(&instance);
+ assertNull(instance, "Expected null result from parcFutureTask_Release();");
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease_PARCObject)
+{
+ PARCBuffer *object = parcBuffer_Allocate(10);
+
+ PARCFutureTask *instance = parcFutureTask_Create(_function, object);
+ parcBuffer_Release(&object);
+
+ assertNotNull(instance, "Expected non-null result from parcFutureTask_Create(_function, object);");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcFutureTask_Acquire, instance);
+
+ parcFutureTask_Release(&instance);
+ assertNull(instance, "Expected null result from parcFutureTask_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_Copy)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *copy = parcFutureTask_Copy(instance);
+ assertTrue(parcFutureTask_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcFutureTask_Release(&instance);
+ parcFutureTask_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_Display)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+ parcFutureTask_Display(instance, 0);
+ parcFutureTask_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_Equals)
+{
+ PARCFutureTask *x = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *y = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *z = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *u1 = parcFutureTask_Create(_function, NULL);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcFutureTask_Release(&x);
+ parcFutureTask_Release(&y);
+ parcFutureTask_Release(&z);
+ parcFutureTask_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_HashCode)
+{
+ PARCFutureTask *x = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *y = parcFutureTask_Create(_function, _function);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcFutureTask_Release(&x);
+ parcFutureTask_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_IsValid)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+ assertTrue(parcFutureTask_IsValid(instance), "Expected parcFutureTask_Create to result in a valid instance.");
+
+ parcFutureTask_Release(&instance);
+ assertFalse(parcFutureTask_IsValid(instance), "Expected parcFutureTask_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_ToJSON)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+
+ PARCJSON *json = parcFutureTask_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcFutureTask_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_ToString)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+
+ char *string = parcFutureTask_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcFutureTask_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcFutureTask_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_Cancel);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_Get);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_IsCancelled);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_IsDone);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_Run);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_RunAndReset);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_Cancel)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ bool parcFutureTask_Cancel(PARCFutureTask *task, bool mayInterruptIfRunning);
+
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_Get)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCFutureTaskResult result = parcFutureTask_Get(task, PARCTimeout_Immediate);
+
+ assertTrue(parcExecution_Is(result.execution, PARCExecution_Timeout), "Expected Timeout, actual %s",
+ parcExecution_GetMessage(result.execution));
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_IsCancelled)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ bool actual = parcFutureTask_IsCancelled(task);
+ assertFalse(actual, "Expected true.");
+
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_IsDone)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ bool actual = parcFutureTask_IsDone(task);
+
+ assertFalse(actual, "Expected false.");
+
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_Run)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ parcFutureTask_Run(task);
+
+ PARCFutureTaskResult actual = parcFutureTask_Get(task, PARCTimeout_Immediate);
+
+ assertTrue(parcFutureTask_IsDone(task), "Expected parcFutureTask_IsDone to be true.");
+ assertTrue(parcExecution_Is(actual.execution, PARCExecution_OK),
+ "Expected OK, actual %s", parcExecution_GetMessage(actual.execution));
+ assertTrue(actual.value == _function, "Expected actual to point to _function");
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_RunAndReset)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ bool actual = parcFutureTask_RunAndReset(task);
+
+ assertTrue(actual, "Expectd parcFutureTask_RunAndReset to return true.");
+ assertFalse(parcFutureTask_IsDone(task), "Expected parcFutureTask_IsDone to be false");
+ parcFutureTask_Release(&task);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_FutureTask);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_Lock.c b/libparc/parc/concurrent/test/test_parc_Lock.c
new file mode 100644
index 00000000..731df04a
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Lock.c
@@ -0,0 +1,352 @@
+/*
+ * 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 "../parc_Lock.c"
+
+#include <stdio.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Lock)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Locking);
+ LONGBOW_RUN_TEST_FIXTURE(WaitNotify);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Lock)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Lock)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCLock *instance = parcLock_Create();
+ assertNotNull(instance, "Expected non-null result from parcLock_Create().");
+
+ parcObjectTesting_AssertAcquire(instance);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLock_Acquire, instance);
+
+ parcLock_Release(&instance);
+ assertNull(instance, "Expected null result from parcLock_Release().");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLock_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcLock_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcLock_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLock_Display)
+{
+ PARCLock *lock = parcLock_Create();
+ parcLock_Display(lock, 0);
+ parcLock_Release(&lock);
+}
+
+LONGBOW_TEST_CASE(Global, parcLock_IsValid)
+{
+ PARCLock *instance = parcLock_Create();
+ assertTrue(parcLock_IsValid(instance), "Expected parcLock_Create to result in a valid instance.");
+
+ parcLock_Release(&instance);
+ assertFalse(parcLock_IsValid(instance), "Expected parcLock_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcLock_ToString)
+{
+ PARCLock *instance = parcLock_Create();
+
+ char *string = parcLock_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcLock_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcLock_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Locking)
+{
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_TryLock_Unlock);
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_TryLock_AlreadyLocked);
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_Lock_Unlock);
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_Lock_AlreadyLocked);
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_Lock_AlreadyLocked);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Locking)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Locking)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Locking, parcLock_TryLock_Unlock)
+{
+ PARCLock *lock = parcLock_Create();
+
+ bool actual = parcLock_TryLock(lock);
+
+ assertTrue(actual, "Expected parcObject_TryLock to succeed.");
+
+ actual = parcLock_IsLocked(lock);
+ assertTrue(actual, "Expected parcObject_IsLocked to be true.");
+
+ actual = parcLock_Unlock(lock);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ actual = parcLock_IsLocked(lock);
+ assertTrue(actual, "Expected parcObject_IsLocked to be false.");
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+LONGBOW_TEST_CASE(Locking, parcLock_Lock_Unlock)
+{
+ PARCLock *lock = parcLock_Create();
+
+ bool actual = parcLock_Lock(lock);
+
+ assertTrue(actual, "Expected parcObject_Lock to succeed.");
+
+ actual = parcLock_IsLocked(lock);
+ assertTrue(actual, "Expected parcObject_IsLocked to be true.");
+
+ actual = parcLock_Unlock(lock);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ actual = parcLock_IsLocked(lock);
+ assertTrue(actual, "Expected parcObject_IsLocked to be false.");
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+LONGBOW_TEST_CASE(Locking, parcLock_TryLock_AlreadyLocked)
+{
+ PARCLock *lock = parcLock_Create();
+
+ bool actual = parcLock_TryLock(lock);
+
+ assertTrue(actual, "Expected parcObject_TryLock to succeed.");
+
+ actual = parcLock_TryLock(lock);
+
+ assertFalse(actual, "Expected parcObject_TryLock to fail when already locked.");
+
+ actual = parcLock_Unlock(lock);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+LONGBOW_TEST_CASE(Locking, parcLock_Lock_AlreadyLocked)
+{
+ PARCLock *lock = parcLock_Create();
+
+ bool actual = parcLock_Lock(lock);
+
+ assertTrue(actual, "Expected parcObject_Lock to succeed.");
+
+ actual = parcLock_Lock(lock);
+
+ assertFalse(actual, "Expected parcObject_Lock to fail when already locked by the same thread.");
+
+ actual = parcLock_Unlock(lock);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+LONGBOW_TEST_FIXTURE(WaitNotify)
+{
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcLock_WaitNotify);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcLock_WaitNotify2);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(WaitNotify)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(WaitNotify)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static int _sharedValue;
+
+static void *
+waiter(void *data)
+{
+ PARCLock *lock = data;
+
+ while (parcLock_TryLock(lock) == false) {
+ ;
+ }
+ parcLock_Wait(lock);
+
+ _sharedValue++;
+ parcLock_Unlock(lock);
+
+ return data;
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcLock_WaitNotify)
+{
+ PARCLock *lock = parcLock_Create();
+
+ _sharedValue = 0;
+
+ pthread_t thread_A;
+ pthread_t thread_B;
+ pthread_t thread_C;
+ pthread_create(&thread_A, NULL, waiter, lock);
+ pthread_create(&thread_B, NULL, waiter, lock);
+ pthread_create(&thread_C, NULL, waiter, lock);
+
+ while (_sharedValue != 3) {
+ while (parcLock_TryLock(lock) == false) {
+ ;
+ }
+ parcLock_Notify(lock);
+ parcLock_Unlock(lock);
+ }
+
+ pthread_join(thread_A, NULL);
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+static void *
+decrement(void *data)
+{
+ PARCLock *lock = data;
+
+ while (parcLock_TryLock(lock) == false) {
+ assertTrue(write(1, ".", 1) == 1, "Write failed.");
+ }
+ while (_sharedValue < 12) {
+ parcLock_Wait(lock);
+ _sharedValue--;
+ }
+ parcLock_Unlock(lock);
+
+ return data;
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcLock_WaitNotify2)
+{
+ PARCLock *lock = parcLock_Create();
+
+ _sharedValue = 0;
+
+ pthread_t thread_A;
+ pthread_create(&thread_A, NULL, decrement, lock);
+
+ _sharedValue = 2;
+ while (parcLock_TryLock(lock) == false) {
+ assertTrue(write(1, ".", 1) == 1, "Write failed.");
+ }
+ while (_sharedValue <= 12) {
+ printf("%d\n", _sharedValue);
+ parcLock_Notify(lock);
+ _sharedValue += 2;
+ }
+ parcLock_Unlock(lock);
+
+ parcLock_Notify(lock);
+ pthread_join(thread_A, NULL);
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Lock);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_Notifier.c b/libparc/parc/concurrent/test/test_parc_Notifier.c
new file mode 100755
index 00000000..97ce6615
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Notifier.c
@@ -0,0 +1,267 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Notifier.c"
+
+#include <sys/time.h>
+#include <pthread.h>
+#include <poll.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Notifier)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Notifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Notifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_Create_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_PauseEvent_NotPaused);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_PauseEvent_AlreadyPaused);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_StartEvents);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_Notify_First);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_Notify_Twice);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_ThreadedTest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ------
+typedef struct test_data {
+ volatile int barrier;
+ PARCNotifier *notifier;
+
+ unsigned notificationsToSend;
+ unsigned notificationsSent;
+
+ unsigned notificationsToRecieve;
+ unsigned notificationsReceived;
+
+ pthread_t producerThread;
+ pthread_t consumerThread;
+} TestData;
+
+
+void *
+consumer(void *p)
+{
+ TestData *data = (TestData *) p;
+ --data->barrier;
+ while (data->barrier) {
+ ;
+ }
+
+ struct pollfd pfd;
+ pfd.fd = parcNotifier_Socket(data->notifier);
+ pfd.events = POLLIN;
+
+ while (data->notificationsReceived < data->notificationsToRecieve) {
+ if (poll(&pfd, 1, -1)) {
+ data->notificationsReceived++;
+ parcNotifier_PauseEvents(data->notifier);
+ usleep(rand() % 1024 + 1024);
+ printf("skipped = %d\n", data->notifier->skippedNotify);
+ parcNotifier_StartEvents(data->notifier);
+ }
+ }
+
+ --data->barrier;
+
+ printf("Consumer exiting: received %d\n", data->notificationsReceived);
+ pthread_exit((void *) NULL);
+}
+
+void *
+producer(void *p)
+{
+ TestData *data = (TestData *) p;
+ --data->barrier;
+ while (data->barrier) {
+ ;
+ }
+
+ while (data->barrier == 0) {
+ if (parcNotifier_Notify(data->notifier)) {
+ }
+ data->notificationsSent++;
+ usleep(rand() % 1024 + 512);
+ }
+
+ printf("Producer exiting: sent %d\n", data->notificationsSent);
+ pthread_exit((void *) NULL);
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_Acquire)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_Create_Release)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_PauseEvent_NotPaused)
+{
+ PARCNotifier *notifier = parcNotifier_Create();
+
+ parcNotifier_PauseEvents(notifier);
+ assertTrue(notifier->paused == 1, "Not paused, got %d expected %d", notifier->paused, 1);
+ assertTrue(notifier->skippedNotify == 0, "Wrong skipped, got %d expected %d", notifier->skippedNotify, 0);
+
+ parcNotifier_Release(&notifier);
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_PauseEvent_AlreadyPaused)
+{
+ PARCNotifier *notifier = parcNotifier_Create();
+
+ parcNotifier_PauseEvents(notifier);
+
+ // now pause again
+ parcNotifier_PauseEvents(notifier);
+
+ assertTrue(notifier->paused == 1, "Not paused, got %d expected %d", notifier->paused, 1);
+ assertTrue(notifier->skippedNotify == 0, "Wrong skipped, got %d expected %d", notifier->skippedNotify, 0);
+
+ parcNotifier_Release(&notifier);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcNotifier_ThreadedTest)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->notifier = parcNotifier_Create();
+ data->notificationsToSend = 10;
+ data->notificationsToRecieve = data->notificationsToSend;
+ data->notificationsSent = 0;
+ data->notificationsReceived = 0;
+ data->barrier = 2;
+
+ pthread_create(&data->consumerThread, NULL, consumer, data);
+ pthread_create(&data->producerThread, NULL, producer, data);
+
+ // wait for them to exit
+ pthread_join(data->producerThread, NULL);
+ pthread_join(data->consumerThread, NULL);
+
+ assertTrue(data->notificationsReceived >= data->notificationsToRecieve,
+ "Did not write all items got %u expected %u\n",
+ data->notificationsReceived,
+ data->notificationsToRecieve);
+
+ parcNotifier_Release(&data->notifier);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_StartEvents)
+{
+ testUnimplemented("unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_Notify_First)
+{
+ PARCNotifier *notifier = parcNotifier_Create();
+
+ bool success = parcNotifier_Notify(notifier);
+ assertTrue(success, "Did not succeed on first notify");
+ assertTrue(notifier->paused == 1, "Not paused, got %d expected %d", notifier->paused, 1);
+ assertTrue(notifier->skippedNotify == 0, "Wrong skipped, got %d expected %d", notifier->skippedNotify, 0);
+
+ parcNotifier_Release(&notifier);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcNotifier_Notify_Twice)
+{
+ PARCNotifier *notifier = parcNotifier_Create();
+
+ parcNotifier_Notify(notifier);
+
+ bool success = parcNotifier_Notify(notifier);
+ assertFalse(success, "Should have failed on second notify");
+ assertTrue(notifier->paused == 1, "Not paused, got %d expected %d", notifier->paused, 1);
+ assertTrue(notifier->skippedNotify == 1, "Wrong skipped, got %d expected %d", notifier->skippedNotify, 1);
+
+ parcNotifier_Release(&notifier);
+}
+
+// ===============================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Notifier);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_RingBuffer_1x1.c b/libparc/parc/concurrent/test/test_parc_RingBuffer_1x1.c
new file mode 100755
index 00000000..a977dfbc
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_RingBuffer_1x1.c
@@ -0,0 +1,325 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_RingBuffer_1x1.c"
+
+#include <sys/time.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_RingBuffer_1x1)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_RingBuffer_1x1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_RingBuffer_1x1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Create_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Create_NonPower2);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Get_Put);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Half);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Full);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Put_ToCapacity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ------
+typedef struct test_ringbuffer {
+ unsigned itemsToWrite;
+ volatile unsigned itemsWritten;
+ volatile unsigned itemsRead;
+ volatile bool blocked;
+
+ PARCRingBuffer1x1 *producerBuffer;
+ PARCRingBuffer1x1 *consumerBuffer;
+
+ pthread_t producerThread;
+ pthread_t consumerThread;
+} TestRingBuffer;
+
+
+void *
+consumer(void *p)
+{
+ TestRingBuffer *trb = (TestRingBuffer *) p;
+
+ while (trb->blocked) {
+ // nothing to do.
+ }
+
+ while (trb->itemsRead < trb->itemsToWrite) {
+ uint32_t *data;
+ bool success = parcRingBuffer1x1_Get(trb->consumerBuffer, (void **) &data);
+ if (success) {
+ assertTrue(*data == trb->itemsRead, "Got out of order item %u expected %u\n", *data, trb->itemsRead);
+ parcMemory_Deallocate((void **) &data);
+ trb->itemsRead++;
+ }
+ }
+
+ pthread_exit((void *) NULL);
+}
+
+void *
+producer(void *p)
+{
+ TestRingBuffer *trb = (TestRingBuffer *) p;
+
+ while (trb->blocked) {
+ // nothing to do
+ }
+
+ while (trb->itemsWritten < trb->itemsToWrite) {
+ uint32_t *data = parcMemory_Allocate(sizeof(uint32_t));
+ assertNotNull(data, "parcMemory_Allocate(%zu) returned NULL", sizeof(uint32_t));
+ *data = trb->itemsWritten;
+
+ bool success = false;
+ do {
+ success = parcRingBuffer1x1_Put(trb->producerBuffer, data);
+ } while (!success);
+ trb->itemsWritten++;
+ }
+
+ pthread_exit((void *) NULL);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Acquire)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcRingBuffer1x1_Create_NonPower2, .event = &LongBowAssertEvent)
+{
+ // this will assert because the number of elements is not a power of 2
+ parcRingBuffer1x1_Create(3, NULL);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Create_Release)
+{
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(1024, NULL);
+ parcRingBuffer1x1_Release(&ring);
+ assertTrue(parcMemory_Outstanding() == 0, "Non-zero memory balance: %u", parcMemory_Outstanding());
+
+ printf("ring buffer entry size: %zu\n", sizeof(PARCRingBuffer1x1));
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Get_Put)
+{
+ TestRingBuffer *trb = parcMemory_AllocateAndClear(sizeof(TestRingBuffer));
+ assertNotNull(trb, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestRingBuffer));
+ trb->producerBuffer = parcRingBuffer1x1_Create(128, NULL);
+ trb->consumerBuffer = parcRingBuffer1x1_Acquire(trb->producerBuffer);
+
+ trb->itemsToWrite = 100000;
+ trb->blocked = true;
+
+ pthread_create(&trb->consumerThread, NULL, consumer, trb);
+ pthread_create(&trb->producerThread, NULL, producer, trb);
+
+ struct timeval t0, t1;
+
+ gettimeofday(&t0, NULL);
+ trb->blocked = false;
+
+ // wait for them to exit
+ pthread_join(trb->producerThread, NULL);
+ pthread_join(trb->consumerThread, NULL);
+ gettimeofday(&t1, NULL);
+
+ timersub(&t1, &t0, &t1);
+
+ assertTrue(trb->itemsWritten == trb->itemsToWrite,
+ "Did not write all items got %u expected %u\n",
+ trb->itemsWritten,
+ trb->itemsToWrite);
+
+ assertTrue(trb->itemsRead == trb->itemsToWrite,
+ "Did not read all items got %u expected %u\n",
+ trb->itemsRead,
+ trb->itemsToWrite);
+
+ double sec = t1.tv_sec + t1.tv_usec * 1E-6;
+
+ printf("Passed %u items in %.6f seconds, %.2f items/sec\n",
+ trb->itemsWritten,
+ sec,
+ trb->itemsWritten / sec);
+
+ parcRingBuffer1x1_Release(&trb->consumerBuffer);
+ parcRingBuffer1x1_Release(&trb->producerBuffer);
+ parcMemory_Deallocate((void **) &trb);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Empty)
+{
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, NULL);
+ uint32_t remaining = parcRingBuffer1x1_Remaining(ring);
+ parcRingBuffer1x1_Release(&ring);
+
+ // -1 because the ring buffer is always -1
+ assertTrue(remaining == capacity - 1, "Got wrong remaining, got %u expecting %u\n", remaining, capacity);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Half)
+{
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, NULL);
+ for (int i = 0; i < capacity / 2; i++) {
+ parcRingBuffer1x1_Put(ring, &i);
+ }
+
+ uint32_t remaining = parcRingBuffer1x1_Remaining(ring);
+ parcRingBuffer1x1_Release(&ring);
+
+ // -1 because the ring buffer is always -1
+ assertTrue(remaining == capacity / 2 - 1, "Got wrong remaining, got %u expecting %u\n", remaining, capacity / 2 - 1);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Full)
+{
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, NULL);
+ for (int i = 0; i < capacity - 1; i++) {
+ parcRingBuffer1x1_Put(ring, &i);
+ }
+
+ uint32_t remaining = parcRingBuffer1x1_Remaining(ring);
+ parcRingBuffer1x1_Release(&ring);
+
+ assertTrue(remaining == 0, "Got wrong remaining, got %u expecting %u\n", remaining, 0);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Put_ToCapacity)
+{
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, NULL);
+ for (int i = 0; i < capacity - 1; i++) {
+ parcRingBuffer1x1_Put(ring, &i);
+ }
+
+ // this next put should fail
+ bool success = parcRingBuffer1x1_Put(ring, &capacity);
+
+ parcRingBuffer1x1_Release(&ring);
+
+ assertFalse(success, "Should have failed on final put because data structure is full\n");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _create);
+ LONGBOW_RUN_TEST_CASE(Local, _destroy);
+ LONGBOW_RUN_TEST_CASE(Local, _isPowerOfTwo);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _create)
+{
+ testUnimplemented("");
+}
+
+static void
+_testDestoryer(void **ptr)
+{
+ parcBuffer_Release((PARCBuffer **) ptr);
+}
+
+LONGBOW_TEST_CASE(Local, _destroy)
+{
+ // put something in the ring and don't remove it. Make sure the destroyer catches it.
+
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, _testDestoryer);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(5);
+ parcRingBuffer1x1_Put(ring, buffer);
+
+ parcRingBuffer1x1_Release(&ring);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance, expected 0 got %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Local, _isPowerOfTwo)
+{
+ struct test_struct {
+ uint32_t value;
+ bool isPow2;
+ } test_vector[] = { { 0, false }, { 1, true }, { 2, true }, { 15, false }, { 16, true }, { 32, true }, { UINT32_MAX, true } };
+
+ for (int i = 0; test_vector[i].value != UINT32_MAX; i++) {
+ bool test = _isPowerOfTwo(test_vector[i].value);
+ assertTrue(test == test_vector[i].isPow2, "Got wrong result for value %u, got %d expected %d\n", test_vector[i].value, test, test_vector[i].isPow2);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_RingBuffer_1x1);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_RingBuffer_NxM.c b/libparc/parc/concurrent/test/test_parc_RingBuffer_NxM.c
new file mode 100755
index 00000000..974da053
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_RingBuffer_NxM.c
@@ -0,0 +1,106 @@
+/*
+ * 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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_RingBuffer_NxM.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_RingBuffer_NxM)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_RingBuffer_NxM)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_RingBuffer_NxM)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _destroy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void
+_testDestoryer(void **ptr)
+{
+ parcBuffer_Release((PARCBuffer **) ptr);
+}
+
+LONGBOW_TEST_CASE(Local, _destroy)
+{
+ // put something in the ring and don't remove it. Make sure the destroyer catches it.
+
+ uint32_t capacity = 128;
+ PARCRingBufferNxM *ring = parcRingBufferNxM_Create(capacity, _testDestoryer);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(5);
+ parcRingBufferNxM_Put(ring, buffer);
+
+ parcRingBufferNxM_Release(&ring);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance, expected 0 got %u", parcMemory_Outstanding());
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_RingBuffer_NxM);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_ScheduledTask.c b/libparc/parc/concurrent/test/test_parc_ScheduledTask.c
new file mode 100644
index 00000000..3655be93
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_ScheduledTask.c
@@ -0,0 +1,244 @@
+/*
+ * 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 "../parc_ScheduledTask.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_ScheduledTask)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_ScheduledTask)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_ScheduledTask)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+void *
+_function(PARCFutureTask *task, void *parameter)
+{
+ return parameter;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+ assertNotNull(instance, "Expected non-null result from parcScheduledTask_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcScheduledTask_Acquire, instance);
+
+ parcScheduledTask_Release(&instance);
+ assertNull(instance, "Expected null result from parcScheduledTask_Release();");
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_Copy)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+ PARCScheduledTask *copy = parcScheduledTask_Copy(instance);
+ assertTrue(parcScheduledTask_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcScheduledTask_Release(&instance);
+ parcScheduledTask_Release(&copy);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_Display)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+ parcScheduledTask_Display(instance, 0);
+ parcScheduledTask_Release(&instance);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_Equals)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *x = parcScheduledTask_Create(task, 0);
+ PARCScheduledTask *y = parcScheduledTask_Create(task, 0);
+ PARCScheduledTask *z = parcScheduledTask_Create(task, 0);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcScheduledTask_Release(&x);
+ parcScheduledTask_Release(&y);
+ parcScheduledTask_Release(&z);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_HashCode)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *x = parcScheduledTask_Create(task, 0);
+ PARCScheduledTask *y = parcScheduledTask_Create(task, 0);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcScheduledTask_Release(&x);
+ parcScheduledTask_Release(&y);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_IsValid)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+ assertTrue(parcScheduledTask_IsValid(instance), "Expected parcScheduledTask_Create to result in a valid instance.");
+
+ parcScheduledTask_Release(&instance);
+ assertFalse(parcScheduledTask_IsValid(instance), "Expected parcScheduledTask_Release to result in an invalid instance.");
+
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_ToJSON)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+
+ PARCJSON *json = parcScheduledTask_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcScheduledTask_Release(&instance);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_ToString)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+
+ char *string = parcScheduledTask_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcScheduledTask_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcScheduledTask_Release(&instance);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ScheduledTask);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/concurrent/test/test_parc_ScheduledThreadPool.c b/libparc/parc/concurrent/test/test_parc_ScheduledThreadPool.c
new file mode 100644
index 00000000..f466d72a
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_ScheduledThreadPool.c
@@ -0,0 +1,301 @@
+/*
+ * 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 "../parc_ScheduledThreadPool.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_ScheduledThreadPool)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_ScheduledThreadPool)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_ScheduledThreadPool)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ longBowTestCase_SetInt(testCase, "initalAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(3);
+ assertNotNull(instance, "Expected non-null result from parcScheduledThreadPool_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcScheduledThreadPool_Acquire, instance);
+ parcScheduledThreadPool_ShutdownNow(instance);
+
+ assertTrue(parcObject_GetReferenceCount(instance) == 1, "Expected 1 reference count. Actual %llu", parcObject_GetReferenceCount(instance));
+
+ parcScheduledThreadPool_Release(&instance);
+ assertNull(instance, "Expected null result from parcScheduledThreadPool_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ longBowTestCase_SetInt(testCase, "initalAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_Copy)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(3);
+ PARCScheduledThreadPool *copy = parcScheduledThreadPool_Copy(instance);
+ assertTrue(parcScheduledThreadPool_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcScheduledThreadPool_ShutdownNow(instance);
+ parcScheduledThreadPool_ShutdownNow(copy);
+
+ parcScheduledThreadPool_Release(&instance);
+ parcScheduledThreadPool_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_Display)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(2);
+ parcScheduledThreadPool_Display(instance, 0);
+ parcScheduledThreadPool_ShutdownNow(instance);
+ parcScheduledThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_Equals)
+{
+ PARCScheduledThreadPool *x = parcScheduledThreadPool_Create(2);
+ PARCScheduledThreadPool *y = parcScheduledThreadPool_Create(2);
+ PARCScheduledThreadPool *z = parcScheduledThreadPool_Create(2);
+ PARCScheduledThreadPool *u1 = parcScheduledThreadPool_Create(3);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcScheduledThreadPool_ShutdownNow(x);
+ parcScheduledThreadPool_ShutdownNow(y);
+ parcScheduledThreadPool_ShutdownNow(z);
+ parcScheduledThreadPool_ShutdownNow(u1);
+
+ parcScheduledThreadPool_Release(&x);
+ parcScheduledThreadPool_Release(&y);
+ parcScheduledThreadPool_Release(&z);
+ parcScheduledThreadPool_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_HashCode)
+{
+ PARCScheduledThreadPool *x = parcScheduledThreadPool_Create(2);
+ PARCScheduledThreadPool *y = parcScheduledThreadPool_Create(2);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcScheduledThreadPool_ShutdownNow(x);
+ parcScheduledThreadPool_ShutdownNow(y);
+
+ parcScheduledThreadPool_Release(&x);
+ parcScheduledThreadPool_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_IsValid)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(2);
+ assertTrue(parcScheduledThreadPool_IsValid(instance), "Expected parcScheduledThreadPool_Create to result in a valid instance.");
+
+ parcScheduledThreadPool_ShutdownNow(instance);
+
+ parcScheduledThreadPool_Release(&instance);
+ assertFalse(parcScheduledThreadPool_IsValid(instance), "Expected parcScheduledThreadPool_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_ToJSON)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(2);
+
+ PARCJSON *json = parcScheduledThreadPool_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcScheduledThreadPool_ShutdownNow(instance);
+ parcScheduledThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_ToString)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(2);
+
+ char *string = parcScheduledThreadPool_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcScheduledThreadPool_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcScheduledThreadPool_ShutdownNow(instance);
+ parcScheduledThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, OneJob);
+ LONGBOW_RUN_TEST_CASE(Specialization, Idle);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcScheduledThreadPool_Schedule);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ longBowTestCase_SetInt(testCase, "initalAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, Idle)
+{
+ PARCScheduledThreadPool *pool = parcScheduledThreadPool_Create(3);
+
+ sleep(2);
+
+ parcScheduledThreadPool_ShutdownNow(pool);
+
+ parcScheduledThreadPool_Release(&pool);
+}
+
+static void *
+_function(PARCFutureTask *task, void *parameter)
+{
+ printf("Hello World\n");
+ return parameter;
+}
+
+LONGBOW_TEST_CASE(Specialization, OneJob)
+{
+ PARCScheduledThreadPool *pool = parcScheduledThreadPool_Create(3);
+
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ parcScheduledThreadPool_Schedule(pool, task, parcTimeout_MilliSeconds(2000));
+ printf("references %lld\n", parcObject_GetReferenceCount(task));
+ parcFutureTask_Release(&task);
+
+ sleep(5);
+
+ parcScheduledThreadPool_ShutdownNow(pool);
+
+ parcScheduledThreadPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcScheduledThreadPool_Schedule)
+{
+ PARCScheduledThreadPool *pool = parcScheduledThreadPool_Create(3);
+
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ parcScheduledThreadPool_Schedule(pool, task, parcTimeout_MilliSeconds(2000));
+
+ parcFutureTask_Release(&task);
+
+ parcScheduledThreadPool_Shutdown(pool);
+// parcScheduledThreadPool_AwaitTermination(pool, PARCTimeout_Never);
+
+// uint64_t count = parcScheduledThreadPool_GetCompletedTaskCount(pool);
+// assertTrue(count == 5, "Expected 5, actual %lld", count);
+
+ parcScheduledThreadPool_ShutdownNow(pool);
+
+ parcScheduledThreadPool_Release(&pool);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ScheduledThreadPool);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_Synchronizer.c b/libparc/parc/concurrent/test/test_parc_Synchronizer.c
new file mode 100755
index 00000000..34d9c711
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Synchronizer.c
@@ -0,0 +1,179 @@
+/*
+ * 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 "../parc_Synchronizer.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Synchronizer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Synchronizer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Synchronizer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+ assertNotNull(instance, "Expeced non-null result from parcSynchronizer_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcSynchronizer_Acquire, instance);
+
+ parcSynchronizer_Release(&instance);
+ assertNull(instance, "Expeced null result from parcSynchronizer_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_TryLock);
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_LockUnlock);
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_TryLock_Fail);
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_IsLocked);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_Display)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+ assertTrue(parcSynchronizer_IsValid(instance), "Expected parcSynchronizer_Create to result in a valid instance.");
+
+ parcSynchronizer_Display(instance, 0);
+ parcSynchronizer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_IsValid)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+ assertTrue(parcSynchronizer_IsValid(instance), "Expected parcSynchronizer_Create to result in a valid instance.");
+
+ parcSynchronizer_Release(&instance);
+ assertFalse(parcSynchronizer_IsValid(instance), "Expected parcSynchronizer_Create to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_TryLock)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+
+ bool actual = parcSynchronizer_TryLock(instance);
+ assertTrue(actual, "Expected parcSynchronizer_TryLock to be successful.");
+
+ parcSynchronizer_Unlock(instance);
+ parcSynchronizer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_TryLock_Fail)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+
+ parcSynchronizer_Lock(instance);
+ bool actual = parcSynchronizer_TryLock(instance);
+ assertFalse(actual, "Expected parcSynchronizer_TryLock to be unsuccessful.");
+
+ parcSynchronizer_Unlock(instance);
+ parcSynchronizer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_LockUnlock)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+
+ parcSynchronizer_Lock(instance);
+ parcSynchronizer_Unlock(instance);
+
+ parcSynchronizer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_IsLocked)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+ assertFalse(parcSynchronizer_IsLocked(instance), "Expected the synchronizer to be unlocked.");
+
+ parcSynchronizer_Lock(instance);
+ assertTrue(parcSynchronizer_IsLocked(instance), "Expected the synchronizer to be unlocked.");
+
+ parcSynchronizer_Unlock(instance);
+ assertFalse(parcSynchronizer_IsLocked(instance), "Expected the synchronizer to be unlocked.");
+
+ parcSynchronizer_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Synchronizer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/concurrent/test/test_parc_Thread.c b/libparc/parc/concurrent/test/test_parc_Thread.c
new file mode 100644
index 00000000..22ca31bf
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Thread.c
@@ -0,0 +1,264 @@
+/*
+ * 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 "../parc_ThreadPool.c"
+
+#include <stdio.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Thread)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Thread)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Thread)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ longBowTestCase_Set(testCase, "object", buffer);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ parcBuffer_Release(&buffer);
+
+ uint32_t initialAllocations = (uint32_t) longBowTestCase_Get(testCase, "initialAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void *
+_function(PARCThread *thread, void *parameter)
+{
+ return NULL;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *thread = parcThread_Create(_function, buffer);
+
+ assertNotNull(thread, "Expected non-null result from parcThread_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcThread_Acquire, thread);
+
+ parcThread_Release(&thread);
+ assertNull(thread, "Expected null result from parcThread_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ longBowTestCase_Set(testCase, "object", buffer);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ parcBuffer_Release(&buffer);
+
+ uint32_t initialAllocations = (uint32_t) longBowTestCase_Get(testCase, "initialAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Compare)
+{
+// testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Copy)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+ PARCThread *copy = parcThread_Copy(instance);
+
+ assertTrue(parcThread_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcThread_Release(&instance);
+ parcThread_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Display)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+ parcThread_Display(instance, 0);
+
+
+ parcThread_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Equals)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *x = parcThread_Create(_function, buffer);
+ PARCThread *y = parcThread_Create(_function, buffer);
+ PARCThread *z = parcThread_Create(_function, buffer);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcThread_Release(&x);
+ parcThread_Release(&y);
+ parcThread_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_HashCode)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *x = parcThread_Create(_function, buffer);
+ PARCThread *y = parcThread_Create(_function, buffer);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcThread_Release(&x);
+ parcThread_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_IsValid)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+ assertTrue(parcThread_IsValid(instance), "Expected parcThread_Create to result in a valid instance.");
+
+
+ parcThread_Release(&instance);
+ assertFalse(parcThread_IsValid(instance), "Expected parcThread_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_ToJSON)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+
+ PARCJSON *json = parcThread_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+
+ parcThread_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_ToString)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+
+ char *string = parcThread_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcThread_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcThread_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Execute);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ uint32_t initialAllocations = (uint32_t) longBowTestCase_Get(testCase, "initialAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Execute)
+{
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Thread);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/concurrent/test/test_parc_ThreadPool.c b/libparc/parc/concurrent/test/test_parc_ThreadPool.c
new file mode 100644
index 00000000..6ed6e4d3
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_ThreadPool.c
@@ -0,0 +1,273 @@
+/*
+ * 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 "../parc_ThreadPool.c"
+
+#include <stdio.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_ThreadPool)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_ThreadPool)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_ThreadPool)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCThreadPool *pool = parcThreadPool_Create(6);
+ assertNotNull(pool, "Expected non-null result from parcThreadPool_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcThreadPool_Acquire, pool);
+
+ parcThreadPool_ShutdownNow(pool);
+
+ parcThreadPool_Release(&pool);
+ assertNull(pool, "Expected null result from parcThreadPool_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Copy)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+ PARCThreadPool *copy = parcThreadPool_Copy(instance);
+ assertTrue(parcThreadPool_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcThreadPool_ShutdownNow(instance);
+ parcThreadPool_ShutdownNow(copy);
+
+ parcThreadPool_Release(&instance);
+ parcThreadPool_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Display)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+ parcThreadPool_Display(instance, 0);
+
+ parcThreadPool_ShutdownNow(instance);
+
+ parcThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Equals)
+{
+ PARCThreadPool *x = parcThreadPool_Create(6);
+ PARCThreadPool *y = parcThreadPool_Create(6);
+ PARCThreadPool *z = parcThreadPool_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcThreadPool_ShutdownNow(x);
+ parcThreadPool_ShutdownNow(y);
+ parcThreadPool_ShutdownNow(z);
+
+ parcThreadPool_Release(&x);
+ parcThreadPool_Release(&y);
+ parcThreadPool_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_HashCode)
+{
+ PARCThreadPool *x = parcThreadPool_Create(6);
+ PARCThreadPool *y = parcThreadPool_Create(6);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcThreadPool_ShutdownNow(x);
+ parcThreadPool_ShutdownNow(y);
+
+ parcThreadPool_Release(&x);
+ parcThreadPool_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_IsValid)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+ assertTrue(parcThreadPool_IsValid(instance), "Expected parcThreadPool_Create to result in a valid instance.");
+
+ parcThreadPool_ShutdownNow(instance);
+
+ parcThreadPool_Release(&instance);
+ assertFalse(parcThreadPool_IsValid(instance), "Expected parcThreadPool_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_ToJSON)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+
+ PARCJSON *json = parcThreadPool_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcThreadPool_ShutdownNow(instance);
+
+ parcThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_ToString)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+
+ char *string = parcThreadPool_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcThreadPool_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcThreadPool_ShutdownNow(instance);
+
+ parcThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Execute);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+void *
+_function(PARCFutureTask *task, void *parameter)
+{
+ printf("Hello World\n");
+ return parameter;
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Execute)
+{
+ dprintf(1, "-----\n");
+ PARCThreadPool *pool = parcThreadPool_Create(6);
+
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+ parcThreadPool_Execute(pool, task);
+ parcThreadPool_Execute(pool, task);
+ parcThreadPool_Execute(pool, task);
+ parcThreadPool_Execute(pool, task);
+ parcThreadPool_Execute(pool, task);
+ parcFutureTask_Release(&task);
+
+ parcThreadPool_Shutdown(pool);
+ bool shutdownSuccess = parcThreadPool_AwaitTermination(pool, PARCTimeout_Never);
+
+ assertTrue(shutdownSuccess, "parcThreadPool_AwaitTermination timed-out");
+
+ uint64_t count = parcThreadPool_GetCompletedTaskCount(pool);
+ assertTrue(count == 5, "Expected 5, actual %lld", count);
+
+
+ parcThreadPool_Release(&pool);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ThreadPool);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/concurrent/test/test_parc_Timer.c b/libparc/parc/concurrent/test/test_parc_Timer.c
new file mode 100644
index 00000000..5bc7ae6c
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Timer.c
@@ -0,0 +1,213 @@
+/*
+ * 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 "../parc_Timer.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Timer)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Object);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Timer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Timer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCTimer *instance = parcTimer_Create();
+ assertNotNull(instance, "Expected non-null result from parcTimer_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcTimer_Acquire, instance);
+
+ parcTimer_Release(&instance);
+ assertNull(instance, "Expected null result from parcTimer_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_Copy)
+{
+ PARCTimer *instance = parcTimer_Create();
+ PARCTimer *copy = parcTimer_Copy(instance);
+ assertTrue(parcTimer_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcTimer_Release(&instance);
+ parcTimer_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_Display)
+{
+ PARCTimer *instance = parcTimer_Create();
+ parcTimer_Display(instance, 0);
+ parcTimer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_Equals)
+{
+ PARCTimer *x = parcTimer_Create();
+ PARCTimer *y = parcTimer_Create();
+ PARCTimer *z = parcTimer_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcTimer_Release(&x);
+ parcTimer_Release(&y);
+ parcTimer_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_HashCode)
+{
+ PARCTimer *x = parcTimer_Create();
+ PARCTimer *y = parcTimer_Create();
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcTimer_Release(&x);
+ parcTimer_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_IsValid)
+{
+ PARCTimer *instance = parcTimer_Create();
+ assertTrue(parcTimer_IsValid(instance), "Expected parcTimer_Create to result in a valid instance.");
+
+ parcTimer_Release(&instance);
+ assertFalse(parcTimer_IsValid(instance), "Expected parcTimer_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_ToJSON)
+{
+ PARCTimer *instance = parcTimer_Create();
+
+ PARCJSON *json = parcTimer_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcTimer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_ToString)
+{
+ PARCTimer *instance = parcTimer_Create();
+
+ char *string = parcTimer_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcTimer_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcTimer_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Timer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+