]> Kevux Git Server - fll/commitdiff
Progress: controller program and f_thread.
authorKevin Day <thekevinday@gmail.com>
Wed, 27 Jan 2021 03:47:57 +0000 (21:47 -0600)
committerKevin Day <thekevinday@gmail.com>
Wed, 27 Jan 2021 03:58:58 +0000 (21:58 -0600)
Add more mutex lock protections.
The thread->data->child is shared and cannot be used as a per thread child process storage, so comment out and add an @fixme.

In the case where the exec() functions return in the child process, the mutexes may not be fully trusted.
All the child process should do is find its way to the exit, deallocating along the way.
Avoid all mutex-related and printf() related functionality where possible.
There were some places where the F_child is not being checked for and returned on but should be checked for and rreturned on.

Work towards improving the mutex locking logic when working with the asynchronous processes, caching, and cancelling.
There is more work to do in this regard.

Sleep interval for the cache cleanup thread now uses the short timer when in test mode and the long timer in non-test mode.

Add a list of functions that need to be completed for t_thread.
Add f_thread_mutex_attribute_t and f_thread_mutex_attributes_t related functions.
Minor cleanups in f_thread.

level_0/f_thread/c/private-thread.c
level_0/f_thread/c/private-thread.h
level_0/f_thread/c/thread-common.h
level_0/f_thread/c/thread.c
level_0/f_thread/c/thread.h
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h
level_3/controller/c/private-thread.c

index da63306413c1ba686aa1acd9e30a03e2af3e1cb3..e80866238e32daa91b3ce0da514b89f52d64c6ee 100644 (file)
@@ -194,6 +194,70 @@ extern "C" {
   }
 #endif // !defined(_di_f_thread_conditions_decrease_) || !defined(_di_f_thread_conditions_decrease_by_) || !defined(_di_f_thread_conditions_increase_) || !defined(_di_f_thread_conditions_increase_by_)
 
+#if !defined(_di_f_thread_mutex_attributes_adjust_) || !defined(_di_f_thread_mutex_attributes_decimate_by_) || !defined(_di_f_thread_mutex_attributes_decrease_) || !defined(_di_f_thread_mutex_attributes_decrease_by_) || !defined(_di_f_thread_mutex_attributes_increase_) || !defined(_di_f_thread_mutex_attributes_increase_by_) || !defined(_di_f_thread_mutex_attributes_resize_)
+  f_status_t private_f_thread_mutex_attribute_delete(f_thread_mutex_attribute_t *attribute) {
+
+    const int error = pthread_mutexattr_destroy(attribute);
+
+    if (error) {
+      if (error == EBUSY) return F_status_set_error(F_busy);
+      if (error == EINVAL) return F_status_set_error(F_parameter);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_f_thread_mutex_attributes_adjust_) || !defined(_di_f_thread_mutex_attributes_decimate_by_) || !defined(_di_f_thread_mutex_attributes_decrease_) || !defined(_di_f_thread_mutex_attributes_decrease_by_) || !defined(_di_f_thread_mutex_attributes_increase_) || !defined(_di_f_thread_mutex_attributes_increase_by_) || !defined(_di_f_thread_mutex_attributes_resize_)
+
+#if !defined(_di_f_thread_mutex_attributes_adjust_) || !defined(_di_f_thread_mutex_attributes_decimate_by_)
+  f_status_t private_f_thread_mutex_attributes_adjust(const f_array_length_t length, f_thread_mutex_attributes_t *attributes) {
+    f_status_t status = F_none;
+
+    for (f_array_length_t i = length; i < attributes->size; ++i) {
+
+      status = private_f_thread_mutex_attribute_delete(&attributes->array[i]);
+      if (F_status_is_error(status)) return status;
+    } // for
+
+    status = f_memory_adjust(attributes->size, length, sizeof(f_thread_mutex_t), (void **) & attributes->array);
+
+    if (F_status_is_error_not(status)) {
+      attributes->size = length;
+
+      if (attributes->used > attributes->size) {
+        attributes->used = length;
+      }
+    }
+
+    return status;
+  }
+#endif // !defined(_di_f_thread_mutex_attributes_adjust_) || !defined(_di_f_thread_mutex_attributes_decimate_by_)
+
+#if !defined(_di_f_thread_mutex_attributes_decrease_) || !defined(_di_f_thread_mutex_attributes_decrease_by_) || !defined(_di_f_thread_mutex_attributes_increase_) || !defined(_di_f_thread_mutex_attributes_increase_by_)
+  f_status_t private_f_thread_mutex_attributes_resize(const f_array_length_t length, f_thread_mutex_attributes_t *attributes) {
+    f_status_t status = F_none;
+
+    for (f_array_length_t i = length; i < attributes->size; ++i) {
+
+      status = private_f_thread_mutex_attribute_delete(&attributes->array[i]);
+      if (F_status_is_error(status)) return status;
+    } // for
+
+    status = f_memory_resize(attributes->size, length, sizeof(f_thread_mutex_t), (void **) & attributes->array);
+
+    if (F_status_is_error_not(status)) {
+      attributes->size = length;
+
+      if (attributes->used > attributes->size) {
+        attributes->used = length;
+      }
+    }
+
+    return status;
+  }
+#endif // !defined(_di_f_thread_mutex_attributes_decrease_) || !defined(_di_f_thread_mutex_attributes_decrease_by_) || !defined(_di_f_thread_mutex_attributes_increase_) || !defined(_di_f_thread_mutex_attributes_increase_by_)
+
 #if !defined(_di_f_thread_mutexs_adjust_) || !defined(_di_f_thread_mutexs_decimate_by_) || !defined(_di_f_thread_mutexs_decrease_) || !defined(_di_f_thread_mutexs_decrease_by_) || !defined(_di_f_thread_mutexs_increase_) || !defined(_di_f_thread_mutexs_increase_by_) || !defined(_di_f_thread_mutexs_resize_)
   f_status_t private_f_thread_mutex_delete(f_thread_mutex_t *mutex) {
 
index f34b41b8d5b9673b27c57a8009110734e58e04d3..a7340ee2a50691ee494bfd1b12b3db3741924143 100644 (file)
@@ -255,10 +255,82 @@ extern "C" {
  *
  * Intended to be shared to each of the different implementation variations.
  *
+ * @param attribute
+ *   The attribute to delete.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_failure (with error bit) on error.
+ *
+ * @see pthread_mutexattr_destroy()
+ *
+ * @see f_thread_mutex_attributes_adjust()
+ * @see f_thread_mutex_attributes_decimate_by()
+ * @see f_thread_mutex_attributes_decrease()
+ * @see f_thread_mutex_attributes_decrease_by()
+ * @see f_thread_mutex_attributes_increase()
+ * @see f_thread_mutex_attributes_increase_by()
+ * @see f_thread_mutex_attributes_resize()
+ */
+#if !defined(_di_f_thread_mutex_attributes_adjust_) || !defined(_di_f_thread_mutex_attributes_decimate_by_) || !defined(_di_f_thread_mutex_attributes_decrease_) || !defined(_di_f_thread_mutex_attributes_decrease_by_) || !defined(_di_f_thread_mutex_attributes_increase_) || !defined(_di_f_thread_mutex_attributes_increase_by_) || !defined(_di_f_thread_mutex_attributes_resize_)
+  extern f_status_t private_f_thread_mutex_attribute_delete(f_thread_mutex_attribute_t *attribute) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_thread_mutex_attributes_adjust_) || !defined(_di_f_thread_mutex_attributes_decimate_by_) || !defined(_di_f_thread_mutex_attributes_decrease_) || !defined(_di_f_thread_mutex_attributes_decrease_by_) || !defined(_di_f_thread_mutex_attributes_increase_) || !defined(_di_f_thread_mutex_attributes_increase_by_) || !defined(_di_f_thread_mutex_attributes_resize_)
+
+/**
+ * Private implementation for resizing.
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
  * @param length
  *   The new size to use.
- * @param mutexs
- *   The mutexs to adjust.
+ * @param attributes
+ *   The attributes to adjust.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   Errors (with error bit) from: f_memory_adjust().
+ *
+ * @see f_memory_adjust()
+ * @see f_thread_mutex_attributes_adjust()
+ * @see f_thread_mutex_attributes_decimate_by()
+ */
+#if !defined(_di_f_thread_mutex_attributes_adjust_) || !defined(_di_f_thread_mutex_attributes_decimate_by_)
+  extern f_status_t private_f_thread_mutex_attributes_adjust(const f_array_length_t length, f_thread_mutex_attributes_t *attributes) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_thread_mutex_attributes_adjust_) || !defined(_di_f_thread_mutex_attributes_decimate_by_)
+
+/**
+ * Private implementation for resizing.
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param length
+ *   The new size to use.
+ * @param attributes
+ *   The attributes to resize.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ *
+ * @see f_memory_resize()
+ * @see f_thread_mutex_attributes_decrease_by()
+ * @see f_thread_mutex_attributes_increase()
+ * @see f_thread_mutex_attributes_increase_by()
+ */
+#if !defined(_di_f_thread_mutex_attributes_decrease_by_) || !defined(_di_f_thread_mutex_attributes_increase_) || !defined(_di_f_thread_mutex_attributes_increase_by_)
+  extern f_status_t private_f_thread_mutex_attributes_resize(const f_array_length_t length, f_thread_mutex_attributes_t *attributes) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_thread_mutex_attributes_decrease_by_) || !defined(_di_f_thread_mutex_attributes_increase_) || !defined(_di_f_thread_mutex_attributes_increase_by_)
+
+/**
+ * Private implementation for deleting (and destroying).
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param mutex
+ *   The mutexs to delete.
  *
  * @return
  *   F_none on success.
index 5bfb6fd05f2ea350b5e64a7e8a43bc23f2f7589e..7f445d7e29c23842625694b8cfedc0f8756d2338 100644 (file)
@@ -341,16 +341,18 @@ extern "C" {
 
   #define f_thread_mutex_attributes_t_initialize { 0, 0, 0 }
 
-  #define f_macro_thread_mutex_attributes_t_resize(status, mutex_attributes, length) f_macro_memory_structure_resize(status, mutex_attributes, f_thread_mutex_attribute_t, length)
-  #define f_macro_thread_mutex_attributes_t_adjust(status, mutex_attributes, length) f_macro_memory_structure_adjust(status, mutex_attributes, f_thread_mutex_attribute_t, length)
+  #define f_macro_thread_mutex_attributes_t_clear(attributes) f_macro_memory_structure_clear(attributes)
 
-  #define f_macro_thread_mutex_attributes_t_delete_simple(mutex_attributes)  f_macro_memory_structure_delete_simple(mutex_attributes, f_thread_mutex_attribute_t)
-  #define f_macro_thread_mutex_attributes_t_destroy_simple(mutex_attributes) f_macro_memory_structure_destroy_simple(mutex_attributes, f_thread_mutex_attribute_t)
+  #define f_macro_thread_mutex_attributes_t_resize(status, attributes, length) status = f_thread_mutex_attributes_resize(length, &attributes);
+  #define f_macro_thread_mutex_attributes_t_adjust(status, attributes, length) status = f_thread_mutex_attributes_adjust(length, &attributes);
 
-  #define f_macro_thread_mutex_attributes_t_increase(status, mutex_attributes)            f_macro_memory_structure_increase(status, mutex_attributes, f_thread_mutex_attribute_t)
-  #define f_macro_thread_mutex_attributes_t_increase_by(status, mutex_attributes, amount) f_macro_memory_structure_increase_by(status, mutex_attributes, f_thread_mutex_attribute_t, amount)
-  #define f_macro_thread_mutex_attributes_t_decrease_by(status, mutex_attributes, amount) f_macro_memory_structure_decrease_by(status, mutex_attributes, f_thread_mutex_attribute_t, amount)
-  #define f_macro_thread_mutex_attributes_t_decimate_by(status, mutex_attributes, amount) f_macro_memory_structure_decimate_by(status, mutex_attributes, f_thread_mutex_attribute_t, amount)
+  #define f_macro_thread_mutex_attributes_t_delete_simple(attributes)  f_thread_mutex_attributes_resize(0, &attributes);
+  #define f_macro_thread_mutex_attributes_t_destroy_simple(attributes) f_thread_mutex_attributes_adjust(0, &attributes);
+
+  #define f_macro_thread_mutex_attributes_t_increase(status, attributes)            status = f_thread_mutex_attributes_increase(attributes);
+  #define f_macro_thread_mutex_attributes_t_increase_by(status, attributes, amount) status = f_thread_mutex_attributes_increase_by(amount, attributes);
+  #define f_macro_thread_mutex_attributes_t_decrease_by(status, attributes, amount) status = f_thread_mutex_attributes_decrease_by(amount, attributes);
+  #define f_macro_thread_mutex_attributes_t_decimate_by(status, attributes, amount) status = f_thread_mutex_attributes_decimate_by(amount, attributes);
 #endif // _di_f_thread_mutex_attributes_t_
 
 /**
index fda017d0e682f18882657cff50fcadb1aaf5081b..0295b95bd439a7ef6d1024cad1ff91f4fbde7295 100644 (file)
@@ -933,7 +933,7 @@ extern "C" {
 #endif // _di_f_thread_join_
 
 #ifndef _di_f_thread_join_try_
-  f_status_t f_thread_try(const f_thread_id_t id, void **result) {
+  f_status_t f_thread_join_try(const f_thread_id_t id, void **result) {
 
     const int error = pthread_tryjoin_np(id, result);
 
@@ -952,7 +952,7 @@ extern "C" {
 #endif // _di_f_thread_join_try_
 
 #ifndef _di_f_thread_join_timed_
-  f_status_t f_thread_timed(const f_thread_id_t id, const struct timespec wait, void **result) {
+  f_status_t f_thread_join_timed(const f_thread_id_t id, const struct timespec wait, void **result) {
 
     const int error = pthread_timedjoin_np(id, result, &wait);
 
@@ -1061,6 +1061,132 @@ extern "C" {
   }
 #endif // _di_f_thread_lock_try_
 
+#ifndef _di_f_thread_mutex_attributes_adjust_
+  f_status_t f_thread_mutex_attributes_adjust(const f_array_length_t length, f_thread_mutex_attributes_t *attributes) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!attributes) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_thread_mutex_attributes_adjust(length, attributes);
+  }
+#endif // _di_f_thread_mutex_attributes_adjust_
+
+#ifndef _di_f_thread_mutex_attributes_decimate_by_
+  f_status_t f_thread_mutex_attributes_decimate_by(const f_array_length_t amount, f_thread_mutex_attributes_t *attributes) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!amount) return F_status_set_error(F_parameter);
+      if (!attributes) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (attributes->size - amount > 0) {
+      return private_f_thread_mutex_attributes_adjust(attributes->size - amount, attributes);
+    }
+
+    return private_f_thread_mutex_attributes_adjust(0, attributes);
+  }
+#endif // _di_f_thread_mutex_attributes_decimate_by_
+
+#ifndef _di_f_thread_mutex_attributes_decrease_by_
+  f_status_t f_thread_mutex_attributes_decrease_by(const f_array_length_t amount, f_thread_mutex_attributes_t *attributes) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!amount) return F_status_set_error(F_parameter);
+      if (!attributes) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (attributes->size - amount > 0) {
+      return private_f_thread_mutex_attributes_resize(attributes->size - amount, attributes);
+    }
+
+    return private_f_thread_mutex_attributes_resize(0, attributes);
+  }
+#endif // _di_f_thread_mutex_attributes_decrease_by_
+
+#ifndef _di_f_thread_mutex_attribute_create_
+  f_status_t f_thread_mutex_attribute_create(f_thread_mutex_attribute_t *attribute) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!attribute) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    const int error = pthread_mutexattr_init(attribute);
+
+    // @todo figure out the error codes and update accordingly.
+    if (error) {
+      if (error == EAGAIN) return F_status_set_error(F_resource_not);
+      if (error == EBUSY) return F_status_set_error(F_busy);
+      if (error == EINVAL) return F_status_set_error(F_parameter);
+      if (error == ENOMEM) return F_status_set_error(F_memory_not);
+      if (error == EPERM) return F_status_set_error(F_prohibited);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // _di_f_thread_mutex_attribute_create_
+
+#ifndef _di_f_thread_mutex_attribute_delete_
+  f_status_t f_thread_mutex_attribute_delete(f_thread_mutex_attribute_t *attribute) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!attribute) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_thread_mutex_attribute_delete(attribute);
+  }
+#endif // _di_f_thread_mutex_attribute_delete_
+
+#ifndef _di_f_thread_mutex_attributes_increase_
+  f_status_t f_thread_mutex_attributes_increase(f_thread_mutex_attributes_t *attributes) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!attributes) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (attributes->used + 1 > attributes->size) {
+      f_array_length_t size = attributes->used + f_memory_default_allocation_step;
+
+      if (size > f_array_length_t_size) {
+        if (attributes->used + 1 > f_array_length_t_size) {
+          return F_status_set_error(F_array_too_large);
+        }
+
+        size = f_array_length_t_size;
+      }
+
+      return private_f_thread_mutex_attributes_resize(size, attributes);
+    }
+
+    return F_data_not;
+  }
+#endif // _di_f_thread_mutex_attributes_increase_
+
+#ifndef _di_f_thread_mutex_attributes_increase_by_
+  f_status_t f_thread_mutex_attributes_increase_by(const f_array_length_t amount, f_thread_mutex_attributes_t *attributes) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!amount) return F_status_set_error(F_parameter);
+      if (!attributes) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (attributes->used + amount > attributes->size) {
+      if (attributes->used + amount > f_array_length_t_size) {
+        return F_status_set_error(F_array_too_large);
+      }
+
+      return private_f_thread_mutex_attributes_resize(attributes->used + amount, attributes);
+    }
+
+    return F_data_not;
+  }
+#endif // _di_f_thread_mutex_attributes_increase_by_
+
+#ifndef _di_f_thread_mutex_attributes_resize_
+  f_status_t f_thread_mutex_attributes_resize(const f_array_length_t length, f_thread_mutex_attributes_t *attributes) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!attributes) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_thread_mutex_attributes_resize(length, attributes);
+  }
+#endif // _di_f_thread_mutex_attributes_resize_
+
 #ifndef _di_f_thread_mutex_create_
   f_status_t f_thread_mutex_create(f_thread_mutex_attribute_t * const attribute, f_thread_mutex_t *mutex) {
     #ifndef _di_level_0_parameter_checking_
index 13e8e0dc52cac8c2323bdcaa3df00132965f9ceb..35a9c0656043c5a38a5d8ff7e8ce6d7c62c1b143 100644 (file)
 #ifndef _F_thread_h
 #define _F_thread_h
 
+// @todo pthread_attr_getstackaddr()
+// @todo pthread_attr_getstacksize()
+// @todo pthread_attr_setstackaddr()
+// @todo pthread_attr_setstacksize()
+// @todo pthread_barrier_destroy
+// @todo pthread_barrier_init
+// @todo pthread_barrier_wait
+// @todo pthread_barrierattr_destroy
+// @todo pthread_barrierattr_getpshared
+// @todo pthread_barrierattr_init
+// @todo pthread_barrierattr_setpshared
+// @todo pthread_condattr_getclock
+// @todo pthread_condattr_getpshared
+// @todo pthread_condattr_setclock
+// @todo pthread_condattr_setpshared
+// @todo pthread_getconcurrency
+// @todo pthread_getschedparam
+// @todo pthread_key_delete
+// @todo pthread_mutex_getprioceiling
+// @todo pthread_mutex_setprioceiling
+// @todo pthread_mutex_timedlock
+// @todo pthread_mutexattr_getprioceiling
+// @todo pthread_mutexattr_getprotocol
+// @todo pthread_mutexattr_getpshared
+// @todo pthread_mutexattr_gettype
+// @todo pthread_mutexattr_setprioceiling
+// @todo pthread_mutexattr_setprotocol
+// @todo pthread_mutexattr_setpshared
+// @todo pthread_mutexattr_settype
+// @todo pthread_rwlock_destroy
+// @todo pthread_rwlock_init
+// @todo pthread_rwlock_timedrdlock
+// @todo pthread_rwlock_timedwrlock
+// @todo pthread_rwlock_trywrlock
+// @todo pthread_rwlock_unlock
+// @todo pthread_rwlock_wrlock
+// @todo pthread_rwlockattr_destroy
+// @todo pthread_rwlockattr_getpshared
+// @todo pthread_rwlockattr_init
+// @todo pthread_rwlockattr_setpshared
+
 // include pre-requirements
 #define _GNU_SOURCE
 
@@ -696,7 +737,7 @@ extern "C" {
  *   F_supported_not (with error bit) if per-CPU clocks are not supported by the OS.
  *   F_failure (with error bit) on any other error.
  *
- * @see pthread_equal()
+ * @see pthread_getcpuclockid()
  */
 #ifndef _di_f_thread_clock_get_id_
   extern f_status_t f_thread_clock_get_id(const f_thread_id_t id_thread, clockid_t *id_clock);
@@ -753,7 +794,7 @@ extern "C" {
  *   F_parameter (with error bit) if a parameter is invalid.
  *   F_failure (with error bit) on any other error.
  *
- * @see pthread_cond_destroy()
+ * @see pthread_condattr_destroy()
  */
 #ifndef _di_f_thread_condition_attribute_delete_
   extern f_status_t f_thread_condition_attribute_delete(f_thread_condition_attribute_t *attribute);
@@ -1263,7 +1304,7 @@ extern "C" {
  * @see pthread_tryjoin_np()
  */
 #ifndef _di_f_thread_join_try_
-  extern f_status_t f_thread_try(const f_thread_id_t id, void **result);
+  extern f_status_t f_thread_join_try(const f_thread_id_t id, void **result);
 #endif // _di_f_thread_join_try_
 
 /**
@@ -1296,7 +1337,7 @@ extern "C" {
  * @see pthread_timedjoin_np()
  */
 #ifndef _di_f_thread_join_timed_
-  extern f_status_t f_thread_timed(const f_thread_id_t id, const struct timespec wait, void **result);
+  extern f_status_t f_thread_join_timed(const f_thread_id_t id, const struct timespec wait, void **result);
 #endif // _di_f_thread_join_timed_
 
 /**
@@ -1398,6 +1439,176 @@ extern "C" {
 #endif // _di_f_thread_lock_try_
 
 /**
+ * Resize the string attributes array.
+ *
+ * @param length
+ *   The new size to use.
+ * @param attributes
+ *   The string attributes array to resize.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_memory_not (with error bit) on out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_thread_mutex_attributes_adjust_
+  extern f_status_t f_thread_mutex_attributes_adjust(const f_array_length_t length, f_thread_mutex_attributes_t *attributes);
+#endif // _di_f_thread_mutex_attributes_adjust_
+
+/**
+ * Resize the string attributes array to a smaller size.
+ *
+ * This will resize making the array smaller based on (size - given length).
+ * If the given length is too small, then the resize will fail.
+ * This will not shrink the size to less than 0.
+ *
+ * @param amount
+ *   A positive number representing how much to decimate the size by.
+ * @param attributes
+ *   The string attributes array to resize.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_memory_not (with error bit) on out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_thread_mutex_attributes_decimate_by_
+  extern f_status_t f_thread_mutex_attributes_decimate_by(const f_array_length_t amount, f_thread_mutex_attributes_t *attributes);
+#endif // _di_f_thread_mutex_attributes_decimate_by_
+
+/**
+ * Resize the string attributes array to a smaller size.
+ *
+ * This will resize making the array smaller based on (size - given length).
+ * If the given length is too small, then the resize will fail.
+ * This will not shrink the size to less than 0.
+ *
+ * @param amount
+ *   A positive number representing how much to decrease the size by.
+ * @param attributes
+ *   The string attributes array to resize.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_memory_not (with error bit) on out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_thread_mutex_attributes_decrease_by_
+  extern f_status_t f_thread_mutex_attributes_decrease_by(const f_array_length_t amount, f_thread_mutex_attributes_t *attributes);
+#endif // _di_f_thread_mutex_attributes_decrease_by_
+
+/**
+ * Create a thread mutex attribute.
+ *
+ * @param attribute
+ *   The mutex attributes to create.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_busy (with error bit) if the mutex is busy.
+ *   F_memory_not (with error bit) if out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_prohibited (with error bit) if not allowed to perform the operation.
+ *   F_resource_not (with error bit) if max mutexes is reached.
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see pthread_mutexattr_init()
+ */
+#ifndef _di_f_thread_mutex_attribute_create_
+  extern f_status_t f_thread_mutex_attribute_create(f_thread_mutex_attribute_t *attribute);
+#endif // _di_f_thread_mutex_attribute_create_
+
+/**
+ * Delete a thread mutex attribute.
+ *
+ * The pthread_mutexattr_destroy() function has no distinction like the *_destroy() and the *_delete() used by the FLL project.
+ * Therefore there is only this function for both deleting and destroying.
+ *
+ * @param attribute
+ *   The attribute to delete.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_busy (with error bit) if the mutex is busy.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see pthread_mutexattr_destroy()
+ */
+#ifndef _di_f_thread_mutex_attribute_delete_
+  extern f_status_t f_thread_mutex_attribute_delete(f_thread_mutex_attribute_t *attribute);
+#endif // _di_f_thread_mutex_attribute_delete_
+
+/**
+ * Increase the size of the string attributes array, but only if necessary.
+ *
+ * If the given length is too large for the buffer, then attempt to set max buffer size (f_array_length_t_size).
+ * If already set to the maximum buffer size, then the resize will fail.
+ *
+ * @param attributes
+ *   The string attributes array to resize.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not on success, but there is no reason to increase size (used + 1 <= size).
+ *
+ *   F_array_too_large (with error bit) if the new array length is too large.
+ *   F_memory_not (with error bit) on out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_thread_mutex_attributes_increase_
+  extern f_status_t f_thread_mutex_attributes_increase(f_thread_mutex_attributes_t *attributes);
+#endif // _di_f_thread_mutex_attributes_increase_
+
+/**
+ * Resize the string attributes array to a larger size.
+ *
+ * This will resize making the string larger based on the given length.
+ * If the given length is too large for the buffer, then attempt to set max buffer size (f_array_length_t_size).
+ * If already set to the maximum buffer size, then the resize will fail.
+ *
+ * @param amount
+ *   A positive number representing how much to increase the size by.
+ * @param attributes
+ *   The string attributes array to resize.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not on success, but there is no reason to increase size (used + amount <= size).
+ *
+ *   F_memory_not (with error bit) on out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_array_too_large (with error bit) if the new array length is too large.
+ */
+#ifndef _di_f_thread_mutex_attributes_increase_by_
+  extern f_status_t f_thread_mutex_attributes_increase_by(const f_array_length_t amount, f_thread_mutex_attributes_t *attributes);
+#endif // _di_f_thread_mutex_attributes_increase_by_
+
+/**
+ * Resize the string attributes array.
+ *
+ * @param length
+ *   The new size to use.
+ * @param attributes
+ *   The string attributes array to adjust.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_memory_not (with error bit) on out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_thread_mutex_attributes_resize_
+  extern f_status_t f_thread_mutex_attributes_resize(const f_array_length_t length, f_thread_mutex_attributes_t *attributes);
+#endif // _di_f_thread_mutex_attributes_resize_
+
+
+/**
  * Create a thread mutex.
  *
  * @param attribute
index d6caac2901d247b88463c35f7c763c4723d1602b..0cb532cce0e0985a0ae2c8b2cefee5001aa85608 100644 (file)
@@ -623,9 +623,7 @@ extern "C" {
 
           status = controller_rule_execute_foreground(index, item->type, *action, 0, action->parameters, options, &execute_set, thread);
 
-          if (status == F_child) {
-            break;
-          }
+          if (status == F_child) break;
 
           if (F_status_is_error(status)) {
             action->status = F_status_set_error(F_failure);
@@ -644,9 +642,7 @@ extern "C" {
 
           status = controller_rule_execute_foreground(index, item->type, *action, rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, options, &execute_set, thread);
 
-          if (status == F_child) {
-            break;
-          }
+          if (status == F_child) break;
 
           if (F_status_is_error(status)) {
             action->status = F_status_set_error(F_failure);
@@ -664,6 +660,8 @@ extern "C" {
 
           status = controller_rule_execute_pid_with(index, item->type, *action, 0, action->parameters, options, &execute_set, thread);
 
+          if (status == F_child) break;
+
           if (F_status_is_error(status)) {
             action->status = F_status_set_error(F_failure);
 
@@ -693,11 +691,11 @@ extern "C" {
 
           continue;
         }
-
-        if (status == F_child || status == F_signal) break;
       } // for
 
-      if (status == F_child || status == F_signal || F_status_is_error(status) && !(options & controller_rule_option_simulate)) break;
+      if (status == F_child || status == F_signal || F_status_is_error(status) && !(options & controller_rule_option_simulate)){
+         break;
+       }
     } // for
 
     f_macro_string_maps_t_delete_simple(environment);
@@ -720,19 +718,12 @@ extern "C" {
   }
 #endif // _di_controller_rule_execute_
 
-#ifndef _di_controller_rule_execute_pid_with_
-  f_status_t controller_rule_execute_pid_with(const f_array_length_t index, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_t *thread) {
+#ifndef _di_controller_rule_execute_foreground_
+  f_status_t controller_rule_execute_foreground(const f_array_length_t index, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_t *thread) {
 
     f_status_t status = F_none;
     int result = 0;
 
-    // @todo check to see if pid file exists.
-
-    // @todo this needs to support/use an option to designate that the process automatically forks in the background.
-    //       in which case fll_execute_program() is called.
-    //       otherwise this needs to call an asynchronous execute process.
-    //       until then, this controller_rule_execute_pid_with() function is not correct and only represents a process that forks to the background.
-
     if (options & controller_rule_option_simulate) {
 
       if (thread->data->error.verbosity != f_console_verbosity_quiet) {
@@ -771,13 +762,25 @@ extern "C" {
       controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) thread->setting->rules.array[index].asynchronous;
 
       // assign the child process id to the asynchronous thread to allow for the cancel process to send appropriate termination signals to the child process.
-      asynchronous->child = result;
+      if (thread->asynchronouss.enabled) {
+        f_thread_mutex_lock(&thread->mutex->asynchronous);
+
+        asynchronous->child = result;
+
+        f_thread_mutex_unlock(&thread->mutex->asynchronous);
+      }
 
-      // have the parent wait for the child process to finish. (@todo see comments above about forking into the background, this code block will need to change.)
+      // have the parent wait for the child process to finish.
       waitpid(asynchronous->child, &result, WUNTRACED | WCONTINUED);
 
       // remove the pid now that waidpid() has returned.
-      asynchronous->child = 0;
+      if (thread->asynchronouss.enabled) {
+        f_thread_mutex_lock(&thread->mutex->asynchronous);
+
+        asynchronous->child = 0;
+
+        f_thread_mutex_unlock(&thread->mutex->asynchronous);
+      }
 
       // this must explicitly check for 0 (as opposed to checking (!result)).
       if (!WIFEXITED(result)) {
@@ -797,7 +800,7 @@ extern "C" {
     }
 
     if (status == F_child) {
-      thread->data->child = result;
+      //thread->data->child = result; // @fixme cant do this!
 
       return F_child;
     }
@@ -823,25 +826,28 @@ extern "C" {
 
       f_thread_mutex_unlock(&thread->mutex->print);
 
-      thread->data->child = 0;
-
-      return F_status_set_error(status);
+      status = F_status_set_error(status);
     }
 
-    // @todo wait for pid file or timeout.
-
-    thread->data->child = 0;
+    // thread->data->child = 0; // @fixme cant do this!
 
     return status;
   }
-#endif // _di_controller_rule_execute_pid_with_
+#endif // _di_controller_rule_execute_foreground_
 
-#ifndef _di_controller_rule_execute_foreground_
-  f_status_t controller_rule_execute_foreground(const f_array_length_t index, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_t *thread) {
+#ifndef _di_controller_rule_execute_pid_with_
+  f_status_t controller_rule_execute_pid_with(const f_array_length_t index, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_t *thread) {
 
     f_status_t status = F_none;
     int result = 0;
 
+    // @todo check to see if pid file exists.
+
+    // @todo this needs to support/use an option to designate that the process automatically forks in the background.
+    //       in which case fll_execute_program() is called.
+    //       otherwise this needs to call an asynchronous execute process.
+    //       until then, this controller_rule_execute_pid_with() function is not correct and only represents a process that forks to the background.
+
     if (options & controller_rule_option_simulate) {
 
       if (thread->data->error.verbosity != f_console_verbosity_quiet) {
@@ -879,14 +885,28 @@ extern "C" {
     if (status == F_parent) {
       controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) thread->setting->rules.array[index].asynchronous;
 
+      result = 0;
+
       // assign the child process id to the asynchronous thread to allow for the cancel process to send appropriate termination signals to the child process.
-      asynchronous->child = result;
+      if (thread->asynchronouss.enabled) {
+        f_thread_mutex_lock(&thread->mutex->asynchronous);
 
-      // have the parent wait for the child process to finish. (@todo see comments above about forking into the background, this code block will need to change.)
-      waitpid(asynchronous->child, &result, WUNTRACED | WCONTINUED);
+        asynchronous->child = result;
+
+        f_thread_mutex_unlock(&thread->mutex->asynchronous);
+
+        // have the parent wait for the child process to finish. (@todo see comments above about forking into the background, this code block will need to change, maybe pass WNOHANG?.)
+        waitpid(asynchronous->child, &result, WUNTRACED | WCONTINUED);
+      }
 
       // remove the pid now that waidpid() has returned.
-      asynchronous->child = 0;
+      if (thread->asynchronouss.enabled) {
+        f_thread_mutex_lock(&thread->mutex->asynchronous);
+
+        asynchronous->child = 0;
+
+        f_thread_mutex_unlock(&thread->mutex->asynchronous);
+      }
 
       // this must explicitly check for 0 (as opposed to checking (!result)).
       if (!WIFEXITED(result)) {
@@ -906,7 +926,7 @@ extern "C" {
     }
 
     if (status == F_child) {
-      thread->data->child = result;
+      //thread->data->child = result; // @fixme cant do this!
 
       return F_child;
     }
@@ -932,14 +952,18 @@ extern "C" {
 
       f_thread_mutex_unlock(&thread->mutex->print);
 
-      status = F_status_set_error(status);
+      //thread->data->child = 0; // @fixme cant do this!
+
+      return F_status_set_error(status);
     }
 
-    thread->data->child = 0;
+    // @todo wait for pid file or timeout.
+
+    //thread->data->child = 0; // @fixme cant do this!
 
     return status;
   }
-#endif // _di_controller_rule_execute_foreground_
+#endif // _di_controller_rule_execute_pid_with_
 
 #ifndef _di_controller_rule_find_loaded_
   f_array_length_t controller_rule_find_loaded(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id) {
@@ -1628,6 +1652,10 @@ extern "C" {
       } // for
     }
 
+    if (status == F_child || status == F_signal) {
+      return status;
+    }
+
     if (!(options & controller_rule_option_wait) && F_status_is_error_not(status)) {
       controller_rule_wait_all(thread);
     }
@@ -1671,13 +1699,13 @@ extern "C" {
       if (F_status_is_error_not(status)) {
         status = controller_rule_execute(index, action, options, thread);
 
-        if (F_status_is_error(status)) {
-          controller_rule_error_print(thread->data->error, *thread->cache_action, F_true);
-        }
-
         if (status == F_child) {
           return F_child;
         }
+
+        if (F_status_is_error(status)) {
+          controller_rule_error_print(thread->data->error, *thread->cache_action, F_true);
+        }
       }
     }
 
@@ -1707,6 +1735,7 @@ extern "C" {
 
     if (F_status_is_error(status)) {
       f_thread_mutex_unlock(&thread->mutex->asynchronous);
+
       return status;
     }
 
@@ -3681,7 +3710,7 @@ extern "C" {
         return;
     }
 
-    controller_rule_t * const rule = &setting->rules.array[index];
+    const controller_rule_t *rule = &setting->rules.array[index];
 
     f_array_length_t i = 0;
     f_array_length_t j = 0;
@@ -3976,30 +4005,35 @@ extern "C" {
     }
 
     controller_rule_t *rule = &thread->setting->rules.array[index];
+    controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) rule->asynchronous;
 
     if (!rule->asynchronous) {
       return;
     }
 
+    // do not need to wait when state is 0.
+    if (!asynchronous->state) {
+      return;
+    }
+
     if (f_thread_mutex_lock_try(&rule->wait) == F_none) {
-      controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) rule->asynchronous;
 
-      if (asynchronous->state == controller_asynchronous_state_done) {
+      if (asynchronous->state != controller_asynchronous_state_joined) {
         f_thread_join(asynchronous->id, 0);
       }
 
       if (thread->asynchronouss.enabled) {
-        f_thread_mutex_lock(&thread->mutex->asynchronous);
+        if (f_thread_mutex_lock_try(&thread->mutex->asynchronous) == F_none) {
+          if (asynchronous->state) {
+            if (asynchronous->state == controller_asynchronous_state_done) {
+              asynchronous->state = controller_asynchronous_state_joined;
+            }
 
-        if (asynchronous->state) {
-          if (asynchronous->state == controller_asynchronous_state_done) {
-            asynchronous->state = controller_asynchronous_state_joined;
+            controller_macro_cache_action_t_clear(asynchronous->cache);
           }
 
-          controller_macro_cache_action_t_clear(asynchronous->cache);
+          f_thread_mutex_unlock(&thread->mutex->asynchronous);
         }
-
-        f_thread_mutex_unlock(&thread->mutex->asynchronous);
       }
 
       f_thread_mutex_unlock(&rule->wait);
@@ -4009,8 +4043,10 @@ extern "C" {
       // a wait lock is already in place, which will also be responsible for thread joining.
       // this can therefore immediately unlock and return.
       f_thread_mutex_lock(&rule->wait);
+
       f_thread_mutex_unlock(&rule->wait);
     }
+
   }
 #endif // _di_controller_rule_wait_for_
 
index 7730b4c3b85bb53570ffad0ca1dc57caccefa4e4..0de920ed5863ac8e0e2e3fe6018d0934151daee3 100644 (file)
@@ -259,10 +259,7 @@ extern "C" {
 #endif // _di_controller_rule_execute_
 
 /**
- * Perform an execution of the given rule in the foreground or background and creating a PID file.
- *
- * When this is synchronous, this will wait for the PID file to be generated before continuing.
- * When this is asynchronous, this will continue on adding the rule id and action to the asynchronous list.
+ * Perform an execution of the given rule in the foreground.
  *
  * @param index
  *   The index location in the rules running this action.
@@ -291,7 +288,6 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_busy on successful execute in asynchronous mode (executed process may or may not fail later on).
  *   F_child on child process exiting.
  *   F_signal on (exit) signal received.
  *
@@ -299,12 +295,15 @@ extern "C" {
  *
  * @see fll_execute_program()
  */
-#ifndef _di_controller_rule_execute_pid_with_
-  extern f_status_t controller_rule_execute_pid_with(const f_array_length_t index, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_t *thread) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_rule_execute_pid_with_
+#ifndef _di_controller_rule_execute_foreground_
+  extern f_status_t controller_rule_execute_foreground(const f_array_length_t index, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_t *thread) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_execute_foreground_
 
 /**
- * Perform an execution of the given rule in the foreground.
+ * Perform an execution of the given rule in the foreground or background and creating a PID file.
+ *
+ * When this is synchronous, this will wait for the PID file to be generated before continuing.
+ * When this is asynchronous, this will continue on adding the rule id and action to the asynchronous list.
  *
  * @param index
  *   The index location in the rules running this action.
@@ -333,6 +332,7 @@ extern "C" {
  *
  * @return
  *   F_none on success.
+ *   F_busy on successful execute in asynchronous mode (executed process may or may not fail later on).
  *   F_child on child process exiting.
  *   F_signal on (exit) signal received.
  *
@@ -340,9 +340,9 @@ extern "C" {
  *
  * @see fll_execute_program()
  */
-#ifndef _di_controller_rule_execute_foreground_
-  extern f_status_t controller_rule_execute_foreground(const f_array_length_t index, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_t *thread) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_rule_execute_foreground_
+#ifndef _di_controller_rule_execute_pid_with_
+  extern f_status_t controller_rule_execute_pid_with(const f_array_length_t index, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_t *thread) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_execute_pid_with_
 
 /**
  * Search the already loaded rules to see if one is found.
index c8527882b87d019aad648560d8008130b2afeb38..ba985c96d180a2adad8d7790c5108ba6d5d92cf0 100644 (file)
@@ -13,28 +13,35 @@ extern "C" {
   void * controller_thread_asynchronous(void *arguments) {
 
     controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) arguments;
-    controller_thread_t thread = controller_thread_t_initialize;
+    controller_thread_t *thread_main = (controller_thread_t *) asynchronous->thread;
 
-    {
-      controller_thread_t *thread_main = (controller_thread_t *) asynchronous->thread;
+    if (!thread_main->asynchronouss.enabled) {
+      return 0;
+    }
 
-      if (!thread_main->asynchronouss.enabled) {
-        return 0;
-      }
+    controller_thread_t thread = controller_thread_t_initialize;
 
-      f_thread_mutex_lock(&thread_main->setting->rules.array[asynchronous->index].lock);
+    f_thread_mutex_lock(&thread_main->setting->rules.array[asynchronous->index].lock);
 
-      thread.cache_main = thread_main->cache_main;
-      thread.cache_action = &asynchronous->cache;
-      thread.data = thread_main->data;
-      thread.mutex = thread_main->mutex;
-      thread.setting = thread_main->setting;
-      thread.stack = &asynchronous->stack;
+    thread.cache_main = thread_main->cache_main;
+    thread.cache_action = &asynchronous->cache;
+    thread.data = thread_main->data;
+    thread.mutex = thread_main->mutex;
+    thread.setting = thread_main->setting;
+    thread.stack = &asynchronous->stack;
+
+    if (controller_rule_process(asynchronous->index, asynchronous->action, asynchronous->options, &thread) == F_child) {
+      // @todo consider returning 1 to designate that this is a child process exiting.
+      return 0;
     }
 
-    controller_rule_process(asynchronous->index, asynchronous->action, asynchronous->options, &thread);
+    if (thread.asynchronouss.enabled) {
+      //f_thread_mutex_lock(&thread_main->mutex->asynchronous);
+
+      asynchronous->state = controller_asynchronous_state_done;
 
-    asynchronous->state = controller_asynchronous_state_done;
+      //f_thread_mutex_unlock(&thread_main->mutex->asynchronous);
+    }
 
     f_thread_mutex_unlock(&thread.setting->rules.array[asynchronous->index].lock);
 
@@ -47,20 +54,26 @@ extern "C" {
 
     thread->asynchronouss.enabled = F_false;
 
-    f_thread_mutex_lock(&thread->mutex->asynchronous);
-
     f_array_length_t i = 0;
 
+    f_thread_mutex_lock(&thread->mutex->asynchronous);
+
     for (; i < thread->asynchronouss.used; ++i) {
 
       if (!thread->asynchronouss.array[i].state) continue;
 
-      if (thread->asynchronouss.array[i].child > 0) {
-        f_signal_send(F_signal_termination, thread->asynchronouss.array[i].child);
+      if (thread->asynchronouss.array[i].state == controller_asynchronous_state_active) {
+        if (thread->asynchronouss.array[i].child > 0) {
+          f_signal_send(F_signal_termination, thread->asynchronouss.array[i].child);
+        }
+
+        thread->asynchronouss.array[i].state = controller_asynchronous_state_done;
       }
 
-      // @todo perhaps a timed join here where if it takes to long, try sending a kill signal to the child process.
-      f_thread_join(thread->asynchronouss.array[i].id, 0);
+      if (thread->asynchronouss.array[i].state == controller_asynchronous_state_done) {
+        // @todo perhaps a timed join here where if it takes to long, try sending a kill signal to the child process.
+        f_thread_join(thread->asynchronouss.array[i].id, 0);
+      }
 
       thread->asynchronouss.array[i].state = 0;
 
@@ -69,11 +82,6 @@ extern "C" {
 
     thread->asynchronouss.used = 0;
 
-    for (i = 0; i < thread->setting->rules.used; ++i) {
-      f_thread_mutex_unlock(&thread->setting->rules.array[i].lock);
-      f_thread_mutex_unlock(&thread->setting->rules.array[i].wait);
-    } // for
-
     f_thread_mutex_unlock(&thread->mutex->print);
     f_thread_mutex_unlock(&thread->mutex->cache);
     f_thread_mutex_unlock(&thread->mutex->rule);
@@ -85,12 +93,13 @@ extern "C" {
   void * controller_thread_cache(void *arguments) {
 
     controller_thread_t *thread = (controller_thread_t *) arguments;
-    controller_rule_t *rule = 0;
+
+    const unsigned int interval = thread->data->parameters[controller_parameter_test].result == f_console_result_found ? controller_thread_cache_cleanup_interval_short : controller_thread_cache_cleanup_interval_long;
 
     f_array_length_t i = 0;
 
     for (;;) {
-      sleep(controller_thread_cache_cleanup_interval_long);
+      sleep(interval);
 
       if (f_thread_mutex_lock_try(&thread->mutex->cache) == F_none) {
         controller_macro_cache_t_delete_simple((*thread->cache_main));
@@ -101,18 +110,23 @@ extern "C" {
           if (thread->asynchronouss.used) {
             for (i = 0; i < thread->asynchronouss.used; ++i) {
 
-              if (thread->asynchronouss.array[i].state == controller_asynchronous_state_done) {
-                f_thread_join(thread->asynchronouss.array[i].id, 0);
-                thread->asynchronouss.array[i].state = controller_asynchronous_state_joined;
-              }
+              if (!thread->asynchronouss.array[i].state) continue;
 
-              if (thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) {
-                controller_macro_asynchronous_t_delete_simple(thread->asynchronouss.array[i]);
+              if (f_thread_mutex_lock_try(&thread->setting->rules.array[thread->asynchronouss.array[i].index].lock) == F_none) {
 
-                thread->asynchronouss.array[i].state = 0;
-              }
+                if (thread->asynchronouss.array[i].state == controller_asynchronous_state_done) {
+                  f_thread_join(thread->asynchronouss.array[i].id, 0);
+                  thread->asynchronouss.array[i].state = controller_asynchronous_state_joined;
+                }
 
-              if (thread->asynchronouss.array[i].state) break;
+                if (thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) {
+                  controller_macro_asynchronous_t_delete_simple(thread->asynchronouss.array[i]);
+
+                  thread->asynchronouss.array[i].state = 0;
+                }
+
+                f_thread_mutex_unlock(&thread->setting->rules.array[thread->asynchronouss.array[i].index].lock);
+              }
             } // for
 
             for (i = thread->asynchronouss.used - 1; thread->asynchronouss.used; --i, --thread->asynchronouss.used) {
@@ -122,8 +136,9 @@ extern "C" {
 
                 thread->asynchronouss.array[i].state = 0;
               }
-
-              if (thread->asynchronouss.array[i].state) break;
+              else if (thread->asynchronouss.array[i].state) {
+                break;
+              }
             } // for
           }
 
@@ -178,7 +193,7 @@ extern "C" {
 
         if (f_file_exists(thread->setting->path_pid.string) == F_true) {
           if (thread->data->error.verbosity != f_console_verbosity_quiet) {
-            if (thread->asynchronouss.enabled) f_thread_mutex_lock(&thread->mutex->print);
+            f_thread_mutex_lock(&thread->mutex->print);
 
             fprintf(thread->data->error.to.stream, "%c", f_string_eol_s[0]);
             fprintf(thread->data->error.to.stream, "%s%sThe pid file '", thread->data->error.context.before->string, thread->data->error.prefix ? thread->data->error.prefix : f_string_empty_s);
@@ -238,6 +253,10 @@ extern "C" {
           }
         }
 
+        if (status == F_child) {
+          return F_child;
+        }
+
         f_thread_mutex_unlock(&thread->mutex->cache);
       }
     }