Commit c015aa4c by Marcus Winter

Merge branch 'development' into embb517_mutex_based_atomics

# Conflicts:
#	base_c/include/embb/base/c/internal/cmake_config.h.in
parents 64f0d2c0 1fe6f342
Embedded Multicore Building Blocks (EMB²) Embedded Multicore Building Blocks (EMB²)
========================================= =========================================
......
...@@ -81,6 +81,8 @@ unsigned int embb_core_count_available(); ...@@ -81,6 +81,8 @@ unsigned int embb_core_count_available();
* The second parameter specifies whether the set is initially empty or contains * The second parameter specifies whether the set is initially empty or contains
* all cores. * all cores.
* *
* \pre \c core_set is not NULL.
*
* \notthreadsafe * \notthreadsafe
*/ */
void embb_core_set_init( void embb_core_set_init(
...@@ -96,6 +98,9 @@ void embb_core_set_init( ...@@ -96,6 +98,9 @@ void embb_core_set_init(
* *
* If the core is already contained in the set, the operation has no effect. * If the core is already contained in the set, the operation has no effect.
* *
* \pre \c core_set is not NULL and \c core_number is smaller than
* embb_core_count_available().
*
* \notthreadsafe * \notthreadsafe
* \see embb_core_set_remove() * \see embb_core_set_remove()
*/ */
...@@ -107,13 +112,16 @@ void embb_core_set_add( ...@@ -107,13 +112,16 @@ void embb_core_set_add(
); );
/** /**
* Removes a core from the specified set. * Removes a core from the specified set.
* *
* If the core is not in the set, the operation has no effect. * If the core is not in the set, the operation has no effect.
* *
* \notthreadsafe * \pre \c core_set is not NULL and \c core_number is smaller than
* \see embb_core_set_add() * embb_core_count_available().
*/ *
* \notthreadsafe
* \see embb_core_set_add()
*/
void embb_core_set_remove( void embb_core_set_remove(
embb_core_set_t* core_set, embb_core_set_t* core_set,
/**< [IN/OUT] Core set to be manipulated */ /**< [IN/OUT] Core set to be manipulated */
...@@ -124,8 +132,11 @@ void embb_core_set_remove( ...@@ -124,8 +132,11 @@ void embb_core_set_remove(
/** /**
* Determines whether a core is contained in the specified set. * Determines whether a core is contained in the specified set.
* *
* \return 0 if the core is not contained in the set, otherwise a number greater * \pre \c core_set is not NULL and \c core_number is smaller than
* than zero. * embb_core_count_available().
*
* \return 0 if the core is not contained in the set, otherwise a number
* greater than zero.
* \notthreadsafe * \notthreadsafe
*/ */
int embb_core_set_contains( int embb_core_set_contains(
...@@ -140,6 +151,8 @@ int embb_core_set_contains( ...@@ -140,6 +151,8 @@ int embb_core_set_contains(
* *
* The result is stored in \c set1. * The result is stored in \c set1.
* *
* \pre \c set1 and \c set2 are not NULL.
*
* \notthreadsafe * \notthreadsafe
* \see embb_core_set_union() * \see embb_core_set_union()
*/ */
...@@ -155,6 +168,8 @@ void embb_core_set_intersection( ...@@ -155,6 +168,8 @@ void embb_core_set_intersection(
* *
* The result is stored in \c set1. * The result is stored in \c set1.
* *
* \pre \c set1 and \c set2 are not NULL.
*
* \notthreadsafe * \notthreadsafe
* \see embb_core_set_intersection() * \see embb_core_set_intersection()
*/ */
...@@ -168,6 +183,8 @@ void embb_core_set_union( ...@@ -168,6 +183,8 @@ void embb_core_set_union(
/** /**
* Returns the number of cores contained in the specified set. * Returns the number of cores contained in the specified set.
* *
* \pre \c core_set is not NULL.
*
* \notthreadsafe * \notthreadsafe
* \return Number of cores in \c core_set * \return Number of cores in \c core_set
*/ */
......
...@@ -67,6 +67,8 @@ int embb_counter_init( ...@@ -67,6 +67,8 @@ int embb_counter_init(
/** /**
* Returns the current value of \c counter. * Returns the current value of \c counter.
* *
* \pre \c counter is not NULL.
*
* \return Current value * \return Current value
* *
* \waitfree * \waitfree
...@@ -79,6 +81,8 @@ unsigned int embb_counter_get( ...@@ -79,6 +81,8 @@ unsigned int embb_counter_get(
/** /**
* Increments \c counter and returns the old value. * Increments \c counter and returns the old value.
* *
* \pre \c counter is not NULL.
*
* \return Old, non-incremented value * \return Old, non-incremented value
* \waitfree * \waitfree
*/ */
...@@ -90,6 +94,8 @@ unsigned int embb_counter_increment( ...@@ -90,6 +94,8 @@ unsigned int embb_counter_increment(
/** /**
* Decrements \c counter and returns the old value. * Decrements \c counter and returns the old value.
* *
* \pre \c counter is not NULL.
*
* \return Old, non-decremented value * \return Old, non-decremented value
* \waitfree * \waitfree
*/ */
...@@ -101,8 +107,8 @@ unsigned int embb_counter_decrement( ...@@ -101,8 +107,8 @@ unsigned int embb_counter_decrement(
/** /**
* Destroys an initialized counter. * Destroys an initialized counter.
* *
* \pre Counter is initialized * \pre \c counter is initialized and not NULL.
* \post Counter is invalid and cannot be used anymore * \post \c counter is invalid and cannot be used anymore
* \waitfree * \waitfree
*/ */
void embb_counter_destroy( void embb_counter_destroy(
......
...@@ -249,6 +249,8 @@ int embb_duration_as_seconds( ...@@ -249,6 +249,8 @@ int embb_duration_as_seconds(
/** /**
* Compares two durations. * Compares two durations.
* *
* \pre \c lhs and \c rhs are not NULL and properly initialized.
*
* \return -1 if \c lhs < \c rhs \n * \return -1 if \c lhs < \c rhs \n
* 0 if \c lhs == \c rhs \n * 0 if \c lhs == \c rhs \n
* 1 if \c lhs > \c rhs * 1 if \c lhs > \c rhs
......
...@@ -58,4 +58,12 @@ ...@@ -58,4 +58,12 @@
*/ */
#cmakedefine EMBB_THREADING_ANALYSIS_MODE #cmakedefine EMBB_THREADING_ANALYSIS_MODE
/**
* Version defines.
*/
#define EMBB_BASE_VERSION_MAJOR ${EMBB_BASE_VERSION_MAJOR}
#define EMBB_BASE_VERSION_MINOR ${EMBB_BASE_VERSION_MINOR}
#define EMBB_BASE_VERSION_PATCH ${EMBB_BASE_VERSION_PATCH}
#endif /* EMBB_BASE_INTERNAL_CMAKE_CONFIG_H_ */ #endif /* EMBB_BASE_INTERNAL_CMAKE_CONFIG_H_ */
...@@ -67,6 +67,7 @@ typedef void(*embb_log_function_t)(void * context, char const * message); ...@@ -67,6 +67,7 @@ typedef void(*embb_log_function_t)(void * context, char const * message);
/** /**
* Default logging function. * Default logging function.
* Writes to the given file (context needs to be a FILE*). * Writes to the given file (context needs to be a FILE*).
* \pre \c context is not NULL.
* \ingroup C_LOG * \ingroup C_LOG
* \threadsafe * \threadsafe
*/ */
......
...@@ -73,6 +73,8 @@ extern "C" { ...@@ -73,6 +73,8 @@ extern "C" {
* *
* Keeps track of freed memory in debug mode. * Keeps track of freed memory in debug mode.
* *
* \pre \c ptr is not NULL.
*
* \threadsafe * \threadsafe
* *
* \see embb_get_bytes_allocated() * \see embb_get_bytes_allocated()
...@@ -161,6 +163,8 @@ extern "C" { ...@@ -161,6 +163,8 @@ extern "C" {
* *
* Keeps track of freed memory in debug mode. * Keeps track of freed memory in debug mode.
* *
* \pre \c ptr is not NULL and was allocated by an aligned method.
*
* \threadsafe * \threadsafe
* *
* \see embb_alloc_aligned(), embb_alloc_cache_aligned(), * \see embb_alloc_aligned(), embb_alloc_cache_aligned(),
......
...@@ -150,7 +150,7 @@ int embb_mutex_unlock( ...@@ -150,7 +150,7 @@ int embb_mutex_unlock(
/** /**
* Destroys a mutex and frees its resources. * Destroys a mutex and frees its resources.
* *
* \pre \c mutex has been initialized * \pre \c mutex is initialized and is not NULL.
* \post \c mutex is uninitialized * \post \c mutex is uninitialized
* \notthreadsafe * \notthreadsafe
* \see embb_mutex_init() * \see embb_mutex_init()
...@@ -233,7 +233,7 @@ int embb_spin_unlock( ...@@ -233,7 +233,7 @@ int embb_spin_unlock(
/** /**
* Destroys a spinlock and frees its resources. * Destroys a spinlock and frees its resources.
* *
* \pre \c spinlock has been initialized * \pre \c spinlock is initialized and is not NULL.
* \post \c spinlock is uninitialized * \post \c spinlock is uninitialized
* \notthreadsafe * \notthreadsafe
* \see embb_spin_init() * \see embb_spin_init()
......
...@@ -112,7 +112,7 @@ void* embb_tss_get( ...@@ -112,7 +112,7 @@ void* embb_tss_get(
* *
* Does not delete the values pointed to. * Does not delete the values pointed to.
* *
* \pre TSS has been created successfully * \pre \c tss has been created successfully and is not NULL.
* \post All slots are deleted * \post All slots are deleted
* \notthreadsafe * \notthreadsafe
* \see embb_tss_create() * \see embb_tss_create()
......
...@@ -89,6 +89,8 @@ int embb_time_in( ...@@ -89,6 +89,8 @@ int embb_time_in(
/** /**
* Compares two time points. * Compares two time points.
* *
* \pre \c lhs and \c rhs are not NULL and properly initialized.
*
* \return -1 if \c lhs < \c rhs \n * \return -1 if \c lhs < \c rhs \n
* 0 if \c lhs == \c rhs \n * 0 if \c lhs == \c rhs \n
* 1 if \c lhs > \c rhs * 1 if \c lhs > \c rhs
......
...@@ -114,7 +114,7 @@ define_or_assign @embb_internal__atomic_or_assign_1_asm@8, byte, dl ...@@ -114,7 +114,7 @@ define_or_assign @embb_internal__atomic_or_assign_1_asm@8, byte, dl
define_store macro name, size, value define_store macro name, size, value
public name public name
name proc name proc
mov size ptr [ecx], value xchg size ptr [ecx], value
ret ret
name endp name endp
endm endm
......
...@@ -107,7 +107,7 @@ define_or_assign embb_internal__atomic_or_assign_1_asm, byte, dl ...@@ -107,7 +107,7 @@ define_or_assign embb_internal__atomic_or_assign_1_asm, byte, dl
define_store macro name, size, value define_store macro name, size, value
public name public name
name proc name proc
mov size ptr [rcx], value xchg size ptr [rcx], value
ret ret
name endp name endp
endm endm
......
...@@ -33,8 +33,9 @@ ...@@ -33,8 +33,9 @@
int embb_condition_wait_for(embb_condition_t* condition_var, int embb_condition_wait_for(embb_condition_t* condition_var,
embb_mutex_t* mutex, embb_mutex_t* mutex,
const embb_duration_t* duration) { const embb_duration_t* duration) {
assert(condition_var != NULL); if (condition_var == NULL || mutex == NULL) {
assert(mutex != NULL); return EMBB_ERROR;
}
embb_time_t time; embb_time_t time;
int status = embb_time_in(&time, duration); int status = embb_time_in(&time, duration);
if (status != EMBB_SUCCESS) { if (status != EMBB_SUCCESS) {
...@@ -46,27 +47,34 @@ int embb_condition_wait_for(embb_condition_t* condition_var, ...@@ -46,27 +47,34 @@ int embb_condition_wait_for(embb_condition_t* condition_var,
#ifdef EMBB_PLATFORM_THREADING_WINTHREADS #ifdef EMBB_PLATFORM_THREADING_WINTHREADS
int embb_condition_init(embb_condition_t* condition_var) { int embb_condition_init(embb_condition_t* condition_var) {
assert(condition_var != NULL); if (condition_var == NULL) {
return EMBB_ERROR;
}
InitializeConditionVariable(condition_var); InitializeConditionVariable(condition_var);
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
int embb_condition_notify_one(embb_condition_t* condition_var) { int embb_condition_notify_one(embb_condition_t* condition_var) {
assert(condition_var != NULL); if (condition_var == NULL) {
return EMBB_ERROR;
}
WakeConditionVariable(condition_var); WakeConditionVariable(condition_var);
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
int embb_condition_notify_all(embb_condition_t* condition_var) { int embb_condition_notify_all(embb_condition_t* condition_var) {
assert(condition_var != NULL); if (condition_var == NULL) {
return EMBB_ERROR;
}
WakeAllConditionVariable(condition_var); WakeAllConditionVariable(condition_var);
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
int embb_condition_wait(embb_condition_t* condition_var, int embb_condition_wait(embb_condition_t* condition_var,
embb_mutex_t* mutex) { embb_mutex_t* mutex) {
assert(condition_var != NULL); if (condition_var == NULL || mutex == NULL) {
assert(mutex != NULL); return EMBB_ERROR;
}
if (SleepConditionVariableCS(condition_var, mutex, INFINITE)) { if (SleepConditionVariableCS(condition_var, mutex, INFINITE)) {
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
...@@ -75,9 +83,9 @@ int embb_condition_wait(embb_condition_t* condition_var, ...@@ -75,9 +83,9 @@ int embb_condition_wait(embb_condition_t* condition_var,
int embb_condition_wait_until(embb_condition_t* condition_var, int embb_condition_wait_until(embb_condition_t* condition_var,
embb_mutex_t* mutex, const embb_time_t* time) { embb_mutex_t* mutex, const embb_time_t* time) {
assert(condition_var != NULL); if (condition_var == NULL || mutex == NULL || time == NULL) {
assert(mutex != NULL); return EMBB_ERROR;
assert(time != NULL); }
/* The Windows API needs a time duration, so we need to convert the given time /* The Windows API needs a time duration, so we need to convert the given time
by using the time now. */ by using the time now. */
embb_time_t now; embb_time_t now;
...@@ -103,7 +111,9 @@ int embb_condition_wait_until(embb_condition_t* condition_var, ...@@ -103,7 +111,9 @@ int embb_condition_wait_until(embb_condition_t* condition_var,
} }
int embb_condition_destroy(embb_condition_t* condition_var) { int embb_condition_destroy(embb_condition_t* condition_var) {
assert(condition_var != NULL); if (condition_var == NULL) {
return EMBB_ERROR;
}
EMBB_UNUSED_IN_RELEASE(condition_var); EMBB_UNUSED_IN_RELEASE(condition_var);
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
...@@ -113,35 +123,42 @@ int embb_condition_destroy(embb_condition_t* condition_var) { ...@@ -113,35 +123,42 @@ int embb_condition_destroy(embb_condition_t* condition_var) {
#ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS #ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS
int embb_condition_init(embb_condition_t* condition_var) { int embb_condition_init(embb_condition_t* condition_var) {
assert(condition_var != NULL); if (condition_var == NULL) {
return EMBB_ERROR;
}
int result = pthread_cond_init(condition_var, NULL); int result = pthread_cond_init(condition_var, NULL);
return result == 0 ? EMBB_SUCCESS : EMBB_ERROR; return result == 0 ? EMBB_SUCCESS : EMBB_ERROR;
} }
int embb_condition_notify_one(embb_condition_t* condition_var) { int embb_condition_notify_one(embb_condition_t* condition_var) {
assert(condition_var != NULL); if (condition_var == NULL) {
return EMBB_ERROR;
}
int result = pthread_cond_signal(condition_var); int result = pthread_cond_signal(condition_var);
return result == 0 ? EMBB_SUCCESS : EMBB_ERROR; return result == 0 ? EMBB_SUCCESS : EMBB_ERROR;
} }
int embb_condition_notify_all(embb_condition_t* condition_var) { int embb_condition_notify_all(embb_condition_t* condition_var) {
assert(condition_var != NULL); if (condition_var == NULL) {
return EMBB_ERROR;
}
int result = pthread_cond_broadcast(condition_var); int result = pthread_cond_broadcast(condition_var);
return result == 0 ? EMBB_SUCCESS : EMBB_ERROR; return result == 0 ? EMBB_SUCCESS : EMBB_ERROR;
} }
int embb_condition_wait(embb_condition_t* condition_var, embb_mutex_t* mutex) { int embb_condition_wait(embb_condition_t* condition_var, embb_mutex_t* mutex) {
assert(condition_var != NULL); if (condition_var == NULL || mutex == NULL) {
assert(mutex != NULL); return EMBB_ERROR;
}
int result = pthread_cond_wait(condition_var, mutex); int result = pthread_cond_wait(condition_var, mutex);
return result == 0 ? EMBB_SUCCESS : EMBB_ERROR; return result == 0 ? EMBB_SUCCESS : EMBB_ERROR;
} }
int embb_condition_wait_until(embb_condition_t* condition_var, int embb_condition_wait_until(embb_condition_t* condition_var,
embb_mutex_t* mutex, const embb_time_t* time) { embb_mutex_t* mutex, const embb_time_t* time) {
assert(condition_var != NULL); if (condition_var == NULL || mutex == NULL || time == NULL) {
assert(mutex != NULL); return EMBB_ERROR;
assert(time != NULL); }
/* Convert EMBB time to Unix time format */ /* Convert EMBB time to Unix time format */
struct timespec unix_time; struct timespec unix_time;
unix_time.tv_sec = time->seconds; unix_time.tv_sec = time->seconds;
...@@ -157,7 +174,9 @@ int embb_condition_wait_until(embb_condition_t* condition_var, ...@@ -157,7 +174,9 @@ int embb_condition_wait_until(embb_condition_t* condition_var,
} }
int embb_condition_destroy(embb_condition_t* condition_var) { int embb_condition_destroy(embb_condition_t* condition_var) {
assert(condition_var != NULL); if (condition_var == NULL) {
return EMBB_ERROR;
}
int status = pthread_cond_destroy(condition_var); int status = pthread_cond_destroy(condition_var);
if (status != 0) { if (status != 0) {
return EMBB_ERROR; return EMBB_ERROR;
......
...@@ -146,13 +146,18 @@ int embb_core_set_contains(const embb_core_set_t* core_set, ...@@ -146,13 +146,18 @@ int embb_core_set_contains(const embb_core_set_t* core_set,
void embb_core_set_intersection(embb_core_set_t* set1, void embb_core_set_intersection(embb_core_set_t* set1,
const embb_core_set_t* set2) { const embb_core_set_t* set2) {
assert(set1 != NULL);
assert(set2 != NULL);
embb_bitset_intersect(&set1->rep, set2->rep); embb_bitset_intersect(&set1->rep, set2->rep);
} }
void embb_core_set_union(embb_core_set_t* set1, const embb_core_set_t* set2) { void embb_core_set_union(embb_core_set_t* set1, const embb_core_set_t* set2) {
assert(set1 != NULL);
assert(set2 != NULL);
embb_bitset_union(&set1->rep, set2->rep); embb_bitset_union(&set1->rep, set2->rep);
} }
unsigned int embb_core_set_count(const embb_core_set_t* core_set) { unsigned int embb_core_set_count(const embb_core_set_t* core_set) {
assert(core_set != NULL);
return embb_bitset_count(&core_set->rep); return embb_bitset_count(&core_set->rep);
} }
...@@ -30,7 +30,9 @@ ...@@ -30,7 +30,9 @@
#include <assert.h> #include <assert.h>
int embb_counter_init(embb_counter_t* counter) { int embb_counter_init(embb_counter_t* counter) {
assert(counter != NULL); if (counter == NULL) {
return EMBB_ERROR;
}
embb_atomic_store_unsigned_int(&(counter->value), 0); embb_atomic_store_unsigned_int(&(counter->value), 0);
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
......
...@@ -46,13 +46,19 @@ const embb_duration_t* embb_duration_zero() { ...@@ -46,13 +46,19 @@ const embb_duration_t* embb_duration_zero() {
int embb_duration_set_nanoseconds(embb_duration_t* duration, int embb_duration_set_nanoseconds(embb_duration_t* duration,
unsigned long long nanoseconds) { unsigned long long nanoseconds) {
assert(duration != NULL); if (duration == NULL) {
return EMBB_ERROR;
}
if (nanoseconds > 0) { if (nanoseconds > 0) {
if (embb_duration_min()->nanoseconds > nanoseconds) { if (embb_duration_min()->nanoseconds > nanoseconds) {
duration->seconds = 0;
duration->nanoseconds = 0;
return EMBB_UNDERFLOW; return EMBB_UNDERFLOW;
} }
const embb_duration_t* max = embb_duration_max(); const embb_duration_t* max = embb_duration_max();
if (max->seconds * 1000000000 + max->nanoseconds < nanoseconds) { if (max->seconds * 1000000000 + max->nanoseconds < nanoseconds) {
duration->seconds = max->seconds;
duration->nanoseconds = max->nanoseconds;
return EMBB_OVERFLOW; return EMBB_OVERFLOW;
} }
} }
...@@ -63,13 +69,19 @@ int embb_duration_set_nanoseconds(embb_duration_t* duration, ...@@ -63,13 +69,19 @@ int embb_duration_set_nanoseconds(embb_duration_t* duration,
int embb_duration_set_microseconds(embb_duration_t* duration, int embb_duration_set_microseconds(embb_duration_t* duration,
unsigned long long microseconds) { unsigned long long microseconds) {
assert(duration != NULL); if (duration == NULL) {
return EMBB_ERROR;
}
if (microseconds > 0) { if (microseconds > 0) {
if (embb_duration_min()->nanoseconds > microseconds*1000) { if (embb_duration_min()->nanoseconds > microseconds*1000) {
duration->seconds = 0;
duration->nanoseconds = 0;
return EMBB_UNDERFLOW; return EMBB_UNDERFLOW;
} }
const embb_duration_t* max = embb_duration_max(); const embb_duration_t* max = embb_duration_max();
if (max->seconds * 1000000 + max->nanoseconds / 1000 < microseconds) { if (max->seconds * 1000000 + max->nanoseconds / 1000 < microseconds) {
duration->seconds = max->seconds;
duration->nanoseconds = max->nanoseconds;
return EMBB_OVERFLOW; return EMBB_OVERFLOW;
} }
} }
...@@ -80,13 +92,19 @@ int embb_duration_set_microseconds(embb_duration_t* duration, ...@@ -80,13 +92,19 @@ int embb_duration_set_microseconds(embb_duration_t* duration,
int embb_duration_set_milliseconds(embb_duration_t* duration, int embb_duration_set_milliseconds(embb_duration_t* duration,
unsigned long long milliseconds) { unsigned long long milliseconds) {
assert(duration != NULL); if (duration == NULL) {
return EMBB_ERROR;
}
if (milliseconds > 0) { if (milliseconds > 0) {
if (embb_duration_min()->nanoseconds > milliseconds*1000000) { if (embb_duration_min()->nanoseconds > milliseconds*1000000) {
duration->seconds = 0;
duration->nanoseconds = 0;
return EMBB_UNDERFLOW; return EMBB_UNDERFLOW;
} }
const embb_duration_t* max = embb_duration_max(); const embb_duration_t* max = embb_duration_max();
if (max->seconds * 1000 + max->nanoseconds / 1000000 < milliseconds) { if (max->seconds * 1000 + max->nanoseconds / 1000000 < milliseconds) {
duration->seconds = max->seconds;
duration->nanoseconds = max->nanoseconds;
return EMBB_OVERFLOW; return EMBB_OVERFLOW;
} }
} }
...@@ -97,13 +115,19 @@ int embb_duration_set_milliseconds(embb_duration_t* duration, ...@@ -97,13 +115,19 @@ int embb_duration_set_milliseconds(embb_duration_t* duration,
int embb_duration_set_seconds(embb_duration_t* duration, int embb_duration_set_seconds(embb_duration_t* duration,
unsigned long long seconds) { unsigned long long seconds) {
assert(duration != NULL); if (duration == NULL) {
return EMBB_ERROR;
}
if (seconds > 0) { if (seconds > 0) {
if (embb_duration_min()->nanoseconds > seconds*1000000000) { if (embb_duration_min()->nanoseconds > seconds*1000000000) {
duration->seconds = 0;
duration->nanoseconds = 0;
return EMBB_UNDERFLOW; return EMBB_UNDERFLOW;
} }
const embb_duration_t* max = embb_duration_max(); const embb_duration_t* max = embb_duration_max();
if (max->seconds + max->nanoseconds / 1000000000 < seconds) { if (max->seconds + max->nanoseconds / 1000000000 < seconds) {
duration->seconds = max->seconds;
duration->nanoseconds = max->nanoseconds;
return EMBB_OVERFLOW; return EMBB_OVERFLOW;
} }
} }
...@@ -113,10 +137,13 @@ int embb_duration_set_seconds(embb_duration_t* duration, ...@@ -113,10 +137,13 @@ int embb_duration_set_seconds(embb_duration_t* duration,
} }
int embb_duration_add(embb_duration_t* lhs, const embb_duration_t* rhs) { int embb_duration_add(embb_duration_t* lhs, const embb_duration_t* rhs) {
assert(lhs != NULL); if (lhs == NULL || rhs == NULL) {
assert(rhs != NULL); return EMBB_ERROR;
}
int carry = (int)((lhs->nanoseconds + rhs->nanoseconds) / 1000000000); int carry = (int)((lhs->nanoseconds + rhs->nanoseconds) / 1000000000);
if (lhs->seconds + rhs->seconds + carry > EMBB_DURATION_MAX_SECONDS) { if (lhs->seconds + rhs->seconds + carry > EMBB_DURATION_MAX_SECONDS) {
lhs->seconds = 0;
lhs->nanoseconds = 0;
return EMBB_OVERFLOW; return EMBB_OVERFLOW;
} }
lhs->nanoseconds = (lhs->nanoseconds + rhs->nanoseconds) % 1000000000; lhs->nanoseconds = (lhs->nanoseconds + rhs->nanoseconds) % 1000000000;
...@@ -126,8 +153,9 @@ int embb_duration_add(embb_duration_t* lhs, const embb_duration_t* rhs) { ...@@ -126,8 +153,9 @@ int embb_duration_add(embb_duration_t* lhs, const embb_duration_t* rhs) {
int embb_duration_as_nanoseconds(const embb_duration_t* duration, int embb_duration_as_nanoseconds(const embb_duration_t* duration,
unsigned long long* nanoseconds) { unsigned long long* nanoseconds) {
assert(duration != NULL); if (duration == NULL || nanoseconds == NULL) {
assert(nanoseconds != NULL); return EMBB_ERROR;
}
if (duration->seconds*1000000000 + duration->nanoseconds > ULLONG_MAX) { if (duration->seconds*1000000000 + duration->nanoseconds > ULLONG_MAX) {
return EMBB_OVERFLOW; return EMBB_OVERFLOW;
} }
...@@ -137,8 +165,9 @@ int embb_duration_as_nanoseconds(const embb_duration_t* duration, ...@@ -137,8 +165,9 @@ int embb_duration_as_nanoseconds(const embb_duration_t* duration,
int embb_duration_as_microseconds(const embb_duration_t* duration, int embb_duration_as_microseconds(const embb_duration_t* duration,
unsigned long long* microseconds) { unsigned long long* microseconds) {
assert(duration != NULL); if (duration == NULL || microseconds == NULL) {
assert(microseconds != NULL); return EMBB_ERROR;
}
if (duration->nanoseconds % 1000 > 0) { if (duration->nanoseconds % 1000 > 0) {
return EMBB_UNDERFLOW; return EMBB_UNDERFLOW;
} }
...@@ -151,8 +180,9 @@ int embb_duration_as_microseconds(const embb_duration_t* duration, ...@@ -151,8 +180,9 @@ int embb_duration_as_microseconds(const embb_duration_t* duration,
int embb_duration_as_milliseconds(const embb_duration_t* duration, int embb_duration_as_milliseconds(const embb_duration_t* duration,
unsigned long long* milliseconds) { unsigned long long* milliseconds) {
assert(duration != NULL); if (duration == NULL || milliseconds == NULL) {
assert(milliseconds != NULL); return EMBB_ERROR;
}
if (duration->nanoseconds % 1000000 > 0) { if (duration->nanoseconds % 1000000 > 0) {
return EMBB_UNDERFLOW; return EMBB_UNDERFLOW;
} }
...@@ -165,12 +195,12 @@ int embb_duration_as_milliseconds(const embb_duration_t* duration, ...@@ -165,12 +195,12 @@ int embb_duration_as_milliseconds(const embb_duration_t* duration,
int embb_duration_as_seconds(const embb_duration_t* duration, int embb_duration_as_seconds(const embb_duration_t* duration,
unsigned long long* seconds) { unsigned long long* seconds) {
assert(duration != NULL); if (duration == NULL || seconds == NULL) {
assert(seconds != NULL); return EMBB_ERROR;
}
if (duration->nanoseconds % 1000000000 > 0) { if (duration->nanoseconds % 1000000000 > 0) {
return EMBB_UNDERFLOW; return EMBB_UNDERFLOW;
} }
assert(duration->nanoseconds % 1000000000 == 0);
if (duration->seconds > ULLONG_MAX) { if (duration->seconds > ULLONG_MAX) {
return EMBB_OVERFLOW; return EMBB_OVERFLOW;
} }
...@@ -180,11 +210,8 @@ int embb_duration_as_seconds(const embb_duration_t* duration, ...@@ -180,11 +210,8 @@ int embb_duration_as_seconds(const embb_duration_t* duration,
int embb_duration_compare(const embb_duration_t* lhs, int embb_duration_compare(const embb_duration_t* lhs,
const embb_duration_t* rhs) { const embb_duration_t* rhs) {
assert(lhs != NULL); assert(lhs != NULL && rhs != NULL);
assert(rhs != NULL); assert(lhs->nanoseconds < 1000000000 && rhs->nanoseconds < 1000000000);
assert(lhs->nanoseconds < 1000000000);
assert(rhs->nanoseconds < 1000000000);
if (lhs->seconds > rhs->seconds) { if (lhs->seconds > rhs->seconds) {
return 1; return 1;
} else if (lhs->seconds < rhs->seconds) { } else if (lhs->seconds < rhs->seconds) {
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <embb/base/c/log.h> #include <embb/base/c/log.h>
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
void embb_log_write_file( void embb_log_write_file(
void * context, void * context,
char const * message) { char const * message) {
assert(context != NULL);
FILE * ff = (FILE*)context; FILE * ff = (FILE*)context;
fprintf(ff, "%s", message); fprintf(ff, "%s", message);
fflush(ff); fflush(ff);
...@@ -90,7 +92,6 @@ void embb_log_write_internal( ...@@ -90,7 +92,6 @@ void embb_log_write_internal(
case EMBB_LOG_LEVEL_NONE: case EMBB_LOG_LEVEL_NONE:
default: default:
log_level_str = " ";
break; break;
} }
#if defined(EMBB_PLATFORM_COMPILER_MSVC) #if defined(EMBB_PLATFORM_COMPILER_MSVC)
......
...@@ -135,6 +135,7 @@ void* embb_alloc_aligned(size_t alignment, size_t size) { ...@@ -135,6 +135,7 @@ void* embb_alloc_aligned(size_t alignment, size_t size) {
void embb_free_aligned(void* ptr) { void embb_free_aligned(void* ptr) {
assert(ptr != NULL); assert(ptr != NULL);
size_t* ptr_conv = (size_t*)ptr; size_t* ptr_conv = (size_t*)ptr;
// If embb_free_aligned is called, the memory block should have been allocated // If embb_free_aligned is called, the memory block should have been allocated
...@@ -193,6 +194,8 @@ void *embb_alloc_aligned(size_t alignment, size_t size) { ...@@ -193,6 +194,8 @@ void *embb_alloc_aligned(size_t alignment, size_t size) {
} }
void embb_free_aligned(void* ptr) { void embb_free_aligned(void* ptr) {
assert(ptr != NULL);
#ifdef EMBB_PLATFORM_COMPILER_MSVC #ifdef EMBB_PLATFORM_COMPILER_MSVC
_aligned_free(ptr); _aligned_free(ptr);
#else #else
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
#ifdef EMBB_PLATFORM_THREADING_WINTHREADS #ifdef EMBB_PLATFORM_THREADING_WINTHREADS
int embb_mutex_init(embb_mutex_t* mutex, int type) { int embb_mutex_init(embb_mutex_t* mutex, int type) {
if (NULL == mutex) {
return EMBB_ERROR;
}
/* Critical sections in Windows are always recursive */ /* Critical sections in Windows are always recursive */
InitializeCriticalSection(mutex); InitializeCriticalSection(mutex);
EMBB_UNUSED(type); EMBB_UNUSED(type);
...@@ -40,11 +43,17 @@ int embb_mutex_init(embb_mutex_t* mutex, int type) { ...@@ -40,11 +43,17 @@ int embb_mutex_init(embb_mutex_t* mutex, int type) {
} }
int embb_mutex_lock(embb_mutex_t* mutex) { int embb_mutex_lock(embb_mutex_t* mutex) {
if (NULL == mutex) {
return EMBB_ERROR;
}
EnterCriticalSection(mutex); EnterCriticalSection(mutex);
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
int embb_mutex_try_lock(embb_mutex_t* mutex) { int embb_mutex_try_lock(embb_mutex_t* mutex) {
if (NULL == mutex) {
return EMBB_ERROR;
}
BOOL success; BOOL success;
success = TryEnterCriticalSection(mutex); success = TryEnterCriticalSection(mutex);
if (success == FALSE) return EMBB_ERROR; if (success == FALSE) return EMBB_ERROR;
...@@ -52,11 +61,15 @@ int embb_mutex_try_lock(embb_mutex_t* mutex) { ...@@ -52,11 +61,15 @@ int embb_mutex_try_lock(embb_mutex_t* mutex) {
} }
int embb_mutex_unlock(embb_mutex_t* mutex) { int embb_mutex_unlock(embb_mutex_t* mutex) {
if (NULL == mutex) {
return EMBB_ERROR;
}
LeaveCriticalSection(mutex); LeaveCriticalSection(mutex);
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
void embb_mutex_destroy(embb_mutex_t* mutex) { void embb_mutex_destroy(embb_mutex_t* mutex) {
assert(NULL != mutex);
DeleteCriticalSection(mutex); DeleteCriticalSection(mutex);
} }
...@@ -65,6 +78,9 @@ void embb_mutex_destroy(embb_mutex_t* mutex) { ...@@ -65,6 +78,9 @@ void embb_mutex_destroy(embb_mutex_t* mutex) {
#ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS #ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS
int embb_mutex_init(embb_mutex_t* mutex, int type) { int embb_mutex_init(embb_mutex_t* mutex, int type) {
if (NULL == mutex) {
return EMBB_ERROR;
}
if (type == EMBB_MUTEX_PLAIN) { if (type == EMBB_MUTEX_PLAIN) {
if (pthread_mutex_init(mutex, NULL) != 0) return EMBB_ERROR; if (pthread_mutex_init(mutex, NULL) != 0) return EMBB_ERROR;
} else { } else {
...@@ -85,6 +101,9 @@ int embb_mutex_init(embb_mutex_t* mutex, int type) { ...@@ -85,6 +101,9 @@ int embb_mutex_init(embb_mutex_t* mutex, int type) {
} }
int embb_mutex_lock(embb_mutex_t* mutex) { int embb_mutex_lock(embb_mutex_t* mutex) {
if (NULL == mutex) {
return EMBB_ERROR;
}
int result = pthread_mutex_lock(mutex); int result = pthread_mutex_lock(mutex);
if (result != 0) { if (result != 0) {
return EMBB_ERROR; return EMBB_ERROR;
...@@ -93,6 +112,9 @@ int embb_mutex_lock(embb_mutex_t* mutex) { ...@@ -93,6 +112,9 @@ int embb_mutex_lock(embb_mutex_t* mutex) {
} }
int embb_mutex_try_lock(embb_mutex_t* mutex) { int embb_mutex_try_lock(embb_mutex_t* mutex) {
if (NULL == mutex) {
return EMBB_ERROR;
}
int result = pthread_mutex_trylock(mutex); int result = pthread_mutex_trylock(mutex);
if (result == 0) { if (result == 0) {
return EMBB_SUCCESS; return EMBB_SUCCESS;
...@@ -104,6 +126,9 @@ int embb_mutex_try_lock(embb_mutex_t* mutex) { ...@@ -104,6 +126,9 @@ int embb_mutex_try_lock(embb_mutex_t* mutex) {
} }
int embb_mutex_unlock(embb_mutex_t* mutex) { int embb_mutex_unlock(embb_mutex_t* mutex) {
if (NULL == mutex) {
return EMBB_ERROR;
}
int result = pthread_mutex_unlock(mutex); int result = pthread_mutex_unlock(mutex);
if (result != 0) { if (result != 0) {
return EMBB_ERROR; return EMBB_ERROR;
...@@ -112,12 +137,16 @@ int embb_mutex_unlock(embb_mutex_t* mutex) { ...@@ -112,12 +137,16 @@ int embb_mutex_unlock(embb_mutex_t* mutex) {
} }
void embb_mutex_destroy(embb_mutex_t* mutex) { void embb_mutex_destroy(embb_mutex_t* mutex) {
assert(NULL != mutex);
pthread_mutex_destroy(mutex); pthread_mutex_destroy(mutex);
} }
#endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */ #endif /* EMBB_PLATFORM_THREADING_POSIXTHREADS */
int embb_spin_init(embb_spinlock_t* spinlock) { int embb_spin_init(embb_spinlock_t* spinlock) {
if (NULL == spinlock) {
return EMBB_ERROR;
}
// For now, store the initial value. In the future will use atomic init // For now, store the initial value. In the future will use atomic init
// function (as soon as available). // function (as soon as available).
embb_atomic_store_int(&spinlock->atomic_spin_variable_, 0); embb_atomic_store_int(&spinlock->atomic_spin_variable_, 0);
...@@ -125,6 +154,9 @@ int embb_spin_init(embb_spinlock_t* spinlock) { ...@@ -125,6 +154,9 @@ int embb_spin_init(embb_spinlock_t* spinlock) {
} }
int embb_spin_lock(embb_spinlock_t* spinlock) { int embb_spin_lock(embb_spinlock_t* spinlock) {
if (NULL == spinlock) {
return EMBB_ERROR;
}
int expected = 0; int expected = 0;
int spins = 1; int spins = 1;
...@@ -143,6 +175,9 @@ int embb_spin_lock(embb_spinlock_t* spinlock) { ...@@ -143,6 +175,9 @@ int embb_spin_lock(embb_spinlock_t* spinlock) {
int embb_spin_try_lock(embb_spinlock_t* spinlock, int embb_spin_try_lock(embb_spinlock_t* spinlock,
unsigned int max_number_spins) { unsigned int max_number_spins) {
if (NULL == spinlock) {
return EMBB_ERROR;
}
if (max_number_spins == 0) if (max_number_spins == 0)
return EMBB_BUSY; return EMBB_BUSY;
...@@ -161,6 +196,9 @@ int embb_spin_try_lock(embb_spinlock_t* spinlock, ...@@ -161,6 +196,9 @@ int embb_spin_try_lock(embb_spinlock_t* spinlock,
} }
int embb_spin_unlock(embb_spinlock_t* spinlock) { int embb_spin_unlock(embb_spinlock_t* spinlock) {
if (NULL == spinlock) {
return EMBB_ERROR;
}
int expected = 1; int expected = 1;
return embb_atomic_compare_and_swap_int(&spinlock->atomic_spin_variable_, return embb_atomic_compare_and_swap_int(&spinlock->atomic_spin_variable_,
&expected, 0) ? &expected, 0) ?
...@@ -168,6 +206,7 @@ int embb_spin_unlock(embb_spinlock_t* spinlock) { ...@@ -168,6 +206,7 @@ int embb_spin_unlock(embb_spinlock_t* spinlock) {
} }
void embb_spin_destroy(embb_spinlock_t* spinlock) { void embb_spin_destroy(embb_spinlock_t* spinlock) {
assert(NULL != spinlock);
// for now, doing nothing here... in future, will call the respective // for now, doing nothing here... in future, will call the respective
// destroy function for atomics... // destroy function for atomics...
EMBB_UNUSED(spinlock); EMBB_UNUSED(spinlock);
......
...@@ -80,10 +80,15 @@ void embb_thread_yield() { ...@@ -80,10 +80,15 @@ void embb_thread_yield() {
int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set,
embb_thread_start_t func, void *arg) { embb_thread_start_t func, void *arg) {
assert(thread != NULL); if (thread == NULL) {
return EMBB_ERROR;
}
thread->embb_internal_arg = (embb_internal_thread_arg_t*) thread->embb_internal_arg = (embb_internal_thread_arg_t*)
embb_alloc(sizeof(embb_internal_thread_arg_t)); embb_alloc(sizeof(embb_internal_thread_arg_t));
if (thread->embb_internal_arg == NULL) return EMBB_NOMEM; if (thread->embb_internal_arg == NULL) {
thread->embb_internal_handle = NULL;
return EMBB_NOMEM;
}
thread->embb_internal_arg->func = func; thread->embb_internal_arg->func = func;
thread->embb_internal_arg->arg = arg; thread->embb_internal_arg->arg = arg;
...@@ -95,6 +100,8 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, ...@@ -95,6 +100,8 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set,
0, /* no creation arguments */ 0, /* no creation arguments */
0); /* no system thread ID */ 0); /* no system thread ID */
if (thread->embb_internal_handle == NULL) { if (thread->embb_internal_handle == NULL) {
embb_free(thread->embb_internal_arg);
thread->embb_internal_arg = NULL;
return EMBB_ERROR; return EMBB_ERROR;
} }
...@@ -118,6 +125,9 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, ...@@ -118,6 +125,9 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set,
} }
int embb_thread_join(embb_thread_t* thread, int* result_code) { int embb_thread_join(embb_thread_t* thread, int* result_code) {
if (thread == NULL) {
return EMBB_ERROR;
}
BOOL success; BOOL success;
DWORD result; DWORD result;
result = WaitForSingleObject(thread->embb_internal_handle, INFINITE); result = WaitForSingleObject(thread->embb_internal_handle, INFINITE);
...@@ -143,6 +153,9 @@ int embb_thread_join(embb_thread_t* thread, int* result_code) { ...@@ -143,6 +153,9 @@ int embb_thread_join(embb_thread_t* thread, int* result_code) {
} }
int embb_thread_equal(const embb_thread_t* lhs, const embb_thread_t* rhs) { int embb_thread_equal(const embb_thread_t* lhs, const embb_thread_t* rhs) {
if (lhs == NULL || rhs == NULL) {
return 0;
}
embb_thread_id_t idLhs = GetThreadId(lhs->embb_internal_handle); embb_thread_id_t idLhs = GetThreadId(lhs->embb_internal_handle);
embb_thread_id_t idRhs = GetThreadId(rhs->embb_internal_handle); embb_thread_id_t idRhs = GetThreadId(rhs->embb_internal_handle);
if (idLhs == idRhs) { if (idLhs == idRhs) {
...@@ -203,6 +216,9 @@ void embb_thread_yield() { ...@@ -203,6 +216,9 @@ void embb_thread_yield() {
int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set,
embb_thread_start_t func, void* arg) { embb_thread_start_t func, void* arg) {
if (thread == NULL) {
return EMBB_ERROR;
}
pthread_attr_t attr; /* Used to set thread affinities */ pthread_attr_t attr; /* Used to set thread affinities */
int status = pthread_attr_init(&attr); int status = pthread_attr_init(&attr);
if (status != 0) return EMBB_ERROR; if (status != 0) return EMBB_ERROR;
...@@ -223,7 +239,11 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, ...@@ -223,7 +239,11 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set,
} }
} }
status = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset); status = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset);
if (status != 0) return EMBB_ERROR; if (status != 0) {
thread->embb_internal_arg = NULL;
thread->embb_internal_handle = 0;
return EMBB_ERROR;
}
#else #else
embb_log_write("base_c", EMBB_LOG_LEVEL_WARNING, "Could not set thread " embb_log_write("base_c", EMBB_LOG_LEVEL_WARNING, "Could not set thread "
"affinity, since no implementation available!\n"); "affinity, since no implementation available!\n");
...@@ -233,6 +253,11 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, ...@@ -233,6 +253,11 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set,
/* Dynamic allocation of thread arguments. Freed on call of join. */ /* Dynamic allocation of thread arguments. Freed on call of join. */
thread->embb_internal_arg = (embb_internal_thread_arg_t*) thread->embb_internal_arg = (embb_internal_thread_arg_t*)
embb_alloc(sizeof(embb_internal_thread_arg_t)); embb_alloc(sizeof(embb_internal_thread_arg_t));
if (thread->embb_internal_arg == NULL) {
thread->embb_internal_handle = 0;
pthread_attr_destroy(&attr);
return EMBB_NOMEM;
}
thread->embb_internal_arg->func = func; thread->embb_internal_arg->func = func;
thread->embb_internal_arg->arg = arg; thread->embb_internal_arg->arg = arg;
...@@ -250,12 +275,17 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set, ...@@ -250,12 +275,17 @@ int embb_thread_create(embb_thread_t* thread, const embb_core_set_t* core_set,
} }
int embb_thread_join(embb_thread_t* thread, int *result_code) { int embb_thread_join(embb_thread_t* thread, int *result_code) {
if (thread == NULL) {
return EMBB_ERROR;
}
int status = 0; int status = 0;
status = pthread_join(thread->embb_internal_handle, NULL); status = pthread_join(thread->embb_internal_handle, NULL);
if (result_code != NULL) { if (thread->embb_internal_arg != NULL) {
*result_code = thread->embb_internal_arg->result; if (result_code != NULL) {
*result_code = thread->embb_internal_arg->result;
}
embb_free(thread->embb_internal_arg);
} }
embb_free(thread->embb_internal_arg);
if (status != 0) { if (status != 0) {
return EMBB_ERROR; return EMBB_ERROR;
} }
...@@ -263,6 +293,9 @@ int embb_thread_join(embb_thread_t* thread, int *result_code) { ...@@ -263,6 +293,9 @@ int embb_thread_join(embb_thread_t* thread, int *result_code) {
} }
int embb_thread_equal(const embb_thread_t* lhs, const embb_thread_t* rhs) { int embb_thread_equal(const embb_thread_t* lhs, const embb_thread_t* rhs) {
if (lhs == NULL || rhs == NULL) {
return 0;
}
return pthread_equal(lhs->embb_internal_handle, rhs->embb_internal_handle); return pthread_equal(lhs->embb_internal_handle, rhs->embb_internal_handle);
} }
......
...@@ -32,7 +32,9 @@ ...@@ -32,7 +32,9 @@
#include <assert.h> #include <assert.h>
int embb_tss_create(embb_tss_t* tss) { int embb_tss_create(embb_tss_t* tss) {
assert(tss != NULL); if (tss == NULL) {
return EMBB_ERROR;
}
tss->size = embb_thread_get_max_count(); tss->size = embb_thread_get_max_count();
tss->values = (void**) embb_alloc_cache_aligned(tss->size * sizeof(void*)); tss->values = (void**) embb_alloc_cache_aligned(tss->size * sizeof(void*));
if (tss->values == NULL) { if (tss->values == NULL) {
...@@ -45,7 +47,9 @@ int embb_tss_create(embb_tss_t* tss) { ...@@ -45,7 +47,9 @@ int embb_tss_create(embb_tss_t* tss) {
} }
int embb_tss_set(embb_tss_t* tss, void* value) { int embb_tss_set(embb_tss_t* tss, void* value) {
assert(tss != NULL); if (tss == NULL) {
return EMBB_ERROR;
}
unsigned int index = 0; unsigned int index = 0;
int status = embb_internal_thread_index(&index); int status = embb_internal_thread_index(&index);
if ((status != EMBB_SUCCESS) || (index >= tss->size)) { if ((status != EMBB_SUCCESS) || (index >= tss->size)) {
...@@ -56,8 +60,12 @@ int embb_tss_set(embb_tss_t* tss, void* value) { ...@@ -56,8 +60,12 @@ int embb_tss_set(embb_tss_t* tss, void* value) {
} }
void* embb_tss_get(const embb_tss_t* tss) { void* embb_tss_get(const embb_tss_t* tss) {
assert(tss != NULL); if (tss == NULL) {
assert(tss->values != NULL); return NULL;
}
if (tss->values == NULL) {
return NULL;
}
unsigned int index = 0; unsigned int index = 0;
int status = embb_internal_thread_index(&index); int status = embb_internal_thread_index(&index);
if ((status != EMBB_SUCCESS) || (index >= tss->size)) { if ((status != EMBB_SUCCESS) || (index >= tss->size)) {
...@@ -68,5 +76,7 @@ void* embb_tss_get(const embb_tss_t* tss) { ...@@ -68,5 +76,7 @@ void* embb_tss_get(const embb_tss_t* tss) {
void embb_tss_delete(embb_tss_t* tss) { void embb_tss_delete(embb_tss_t* tss) {
assert(tss != NULL); assert(tss != NULL);
embb_free_aligned(tss->values); if (tss->values != NULL) {
embb_free_aligned(tss->values);
}
} }
...@@ -33,11 +33,8 @@ void embb_time_now(embb_time_t* time) { ...@@ -33,11 +33,8 @@ void embb_time_now(embb_time_t* time) {
} }
int embb_time_compare(const embb_time_t* lhs, const embb_time_t* rhs) { int embb_time_compare(const embb_time_t* lhs, const embb_time_t* rhs) {
assert(lhs != NULL); assert(lhs != NULL && rhs != NULL);
assert(rhs != NULL); assert(lhs->nanoseconds < 1000000000 && rhs->nanoseconds < 1000000000);
assert(lhs->nanoseconds < 1000000000);
assert(rhs->nanoseconds < 1000000000);
if (lhs->seconds > rhs->seconds) { if (lhs->seconds > rhs->seconds) {
return 1; return 1;
} else if (lhs->seconds < rhs->seconds) { } else if (lhs->seconds < rhs->seconds) {
...@@ -56,8 +53,9 @@ int embb_time_compare(const embb_time_t* lhs, const embb_time_t* rhs) { ...@@ -56,8 +53,9 @@ int embb_time_compare(const embb_time_t* lhs, const embb_time_t* rhs) {
#ifdef EMBB_PLATFORM_THREADING_WINTHREADS #ifdef EMBB_PLATFORM_THREADING_WINTHREADS
int embb_time_in(embb_time_t* time, const embb_duration_t* duration) { int embb_time_in(embb_time_t* time, const embb_duration_t* duration) {
assert(time != NULL); if (time == NULL || duration == NULL) {
assert(duration != NULL); return EMBB_ERROR;
}
/* Get system time */ /* Get system time */
SYSTEMTIME system_time; SYSTEMTIME system_time;
GetLocalTime(&system_time); GetLocalTime(&system_time);
...@@ -87,8 +85,9 @@ int embb_time_in(embb_time_t* time, const embb_duration_t* duration) { ...@@ -87,8 +85,9 @@ int embb_time_in(embb_time_t* time, const embb_duration_t* duration) {
#ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS #ifdef EMBB_PLATFORM_THREADING_POSIXTHREADS
int embb_time_in(embb_time_t* time, const embb_duration_t* duration) { int embb_time_in(embb_time_t* time, const embb_duration_t* duration) {
assert(time != NULL); if (time == NULL || duration == NULL) {
assert(duration != NULL); return EMBB_ERROR;
}
struct timespec unix_time; struct timespec unix_time;
clock_gettime(CLOCK_REALTIME, &unix_time); clock_gettime(CLOCK_REALTIME, &unix_time);
time->seconds = unix_time.tv_sec; time->seconds = unix_time.tv_sec;
......
...@@ -152,6 +152,9 @@ void AllocTest::TestMixedAllocs() { ...@@ -152,6 +152,9 @@ void AllocTest::TestMixedAllocs() {
void* plain = NULL; void* plain = NULL;
plain = embb_alloc(2); plain = embb_alloc(2);
PT_EXPECT_NE(plain, static_cast<void*>(NULL)); PT_EXPECT_NE(plain, static_cast<void*>(NULL));
if (NULL == plain) {
return;
}
allocated = embb_get_bytes_allocated(); allocated = embb_get_bytes_allocated();
#ifdef EMBB_DEBUG #ifdef EMBB_DEBUG
expected += 2 + 2*sizeof(size_t); expected += 2 + 2*sizeof(size_t);
...@@ -162,6 +165,10 @@ void AllocTest::TestMixedAllocs() { ...@@ -162,6 +165,10 @@ void AllocTest::TestMixedAllocs() {
void* aligned = NULL; void* aligned = NULL;
aligned = embb_alloc_aligned(2*sizeof(void*), 2); aligned = embb_alloc_aligned(2*sizeof(void*), 2);
PT_EXPECT_NE(aligned, static_cast<void*>(NULL)); PT_EXPECT_NE(aligned, static_cast<void*>(NULL));
if (NULL == aligned) {
embb_free(plain);
return;
}
allocated = embb_get_bytes_allocated(); allocated = embb_get_bytes_allocated();
#ifdef EMBB_DEBUG #ifdef EMBB_DEBUG
expected += (1 + 1) * 2 * sizeof(void*) + 3 * sizeof(size_t) - 1; expected += (1 + 1) * 2 * sizeof(void*) + 3 * sizeof(size_t) - 1;
...@@ -172,6 +179,11 @@ void AllocTest::TestMixedAllocs() { ...@@ -172,6 +179,11 @@ void AllocTest::TestMixedAllocs() {
void* cache_aligned = NULL; void* cache_aligned = NULL;
cache_aligned = embb_alloc_cache_aligned(2); cache_aligned = embb_alloc_cache_aligned(2);
PT_EXPECT_NE(cache_aligned, static_cast<void*>(NULL)); PT_EXPECT_NE(cache_aligned, static_cast<void*>(NULL));
if (NULL == cache_aligned) {
embb_free(plain);
embb_free_aligned(aligned);
return;
}
allocated = embb_get_bytes_allocated(); allocated = embb_get_bytes_allocated();
#ifdef EMBB_DEBUG #ifdef EMBB_DEBUG
expected += (1 + 1) * EMBB_PLATFORM_CACHE_LINE_SIZE + 3 * sizeof(size_t) - 1; expected += (1 + 1) * EMBB_PLATFORM_CACHE_LINE_SIZE + 3 * sizeof(size_t) - 1;
......
...@@ -50,7 +50,11 @@ void ThreadSpecificStorageTest::Test() { ...@@ -50,7 +50,11 @@ void ThreadSpecificStorageTest::Test() {
size_t rank = partest::TestSuite::GetCurrentThreadID(); size_t rank = partest::TestSuite::GetCurrentThreadID();
void* value = embb_tss_get(&tss_); void* value = embb_tss_get(&tss_);
if (value == NULL) { if (value == NULL) {
int status = embb_tss_set(&tss_, new size_t(rank)); size_t * prank = new size_t(rank);
int status = embb_tss_set(&tss_, prank);
if (EMBB_SUCCESS != status) {
delete prank;
}
PT_EXPECT_EQ(status, EMBB_SUCCESS); PT_EXPECT_EQ(status, EMBB_SUCCESS);
} else { } else {
size_t stored_rank = *static_cast<size_t*>(value); size_t stored_rank = *static_cast<size_t*>(value);
......
...@@ -32,7 +32,10 @@ namespace base { ...@@ -32,7 +32,10 @@ namespace base {
namespace internal { namespace internal {
MutexBase::MutexBase(int mutex_type) : mutex_() { MutexBase::MutexBase(int mutex_type) : mutex_() {
embb_mutex_init(&mutex_, mutex_type); int result = embb_mutex_init(&mutex_, mutex_type);
if (EMBB_SUCCESS != result) {
EMBB_THROW(ErrorException, "Could not initialize mutex.");
}
} }
MutexBase::~MutexBase() { MutexBase::~MutexBase() {
...@@ -40,7 +43,10 @@ MutexBase::~MutexBase() { ...@@ -40,7 +43,10 @@ MutexBase::~MutexBase() {
} }
void MutexBase::Lock() { void MutexBase::Lock() {
embb_mutex_lock(&mutex_); int result = embb_mutex_lock(&mutex_);
if (EMBB_SUCCESS != result) {
EMBB_THROW(ErrorException, "Could not lock mutex.");
}
} }
bool MutexBase::TryLock() { bool MutexBase::TryLock() {
...@@ -49,7 +55,10 @@ bool MutexBase::TryLock() { ...@@ -49,7 +55,10 @@ bool MutexBase::TryLock() {
} }
void MutexBase::Unlock() { void MutexBase::Unlock() {
embb_mutex_unlock(&mutex_); int result = embb_mutex_unlock(&mutex_);
if (EMBB_SUCCESS != result) {
EMBB_THROW(ErrorException, "Could not unlock mutex.");
}
} }
} // namespace internal } // namespace internal
......
...@@ -173,10 +173,6 @@ AtomicTest::TestStressSwap::TestStressSwap( ...@@ -173,10 +173,6 @@ AtomicTest::TestStressSwap::TestStressSwap(
size_t number_threads, size_t number_iterations) size_t number_threads, size_t number_iterations)
: TestUnit("Swap Stress test for Atomics"), swap1_counter(1) : TestUnit("Swap Stress test for Atomics"), swap1_counter(1)
, swap2_counter(2) { , swap2_counter(2) {
bitsets[0] = std::bitset<ATOMIC_TESTS_ITERATIONS * 2 + 1>();
bitsets[1] = std::bitset<ATOMIC_TESTS_ITERATIONS * 2 + 1>();
bitsets[2] = std::bitset<ATOMIC_TESTS_ITERATIONS * 2 + 1>();
PT_ASSERT(number_threads == 1); PT_ASSERT(number_threads == 1);
Pre(&TestStressSwap::Init, this); Pre(&TestStressSwap::Init, this);
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <embb/base/c/internal/unused.h> #include <embb/base/c/internal/unused.h>
#include <embb/base/log.h> #include <embb/base/log.h>
#include <cstring> #include <string>
namespace embb { namespace embb {
namespace base { namespace base {
...@@ -38,7 +38,7 @@ LogTest::LogTest() { ...@@ -38,7 +38,7 @@ LogTest::LogTest() {
CreateUnit("Test all").Add(&LogTest::Test, this); CreateUnit("Test all").Add(&LogTest::Test, this);
} }
static char const * logged_message; static std::string logged_message;
static void test_log_function(void * context, char const * msg) { static void test_log_function(void * context, char const * msg) {
EMBB_UNUSED(context); EMBB_UNUSED(context);
...@@ -48,91 +48,90 @@ static void test_log_function(void * context, char const * msg) { ...@@ -48,91 +48,90 @@ static void test_log_function(void * context, char const * msg) {
void LogTest::Test() { void LogTest::Test() {
using embb::base::Log; using embb::base::Log;
char const * test_msg = "hello"; char const * test_msg = "hello";
char const * null = 0;
Log::SetLogFunction(0, test_log_function); Log::SetLogFunction(0, test_log_function);
Log::SetLogLevel(EMBB_LOG_LEVEL_TRACE); Log::SetLogLevel(EMBB_LOG_LEVEL_TRACE);
logged_message = null; logged_message = "none";
Log::Trace("chn", test_msg); Log::Trace("chn", test_msg);
#ifdef EMBB_DEBUG #ifdef EMBB_DEBUG
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [TRACE] hello")); PT_EXPECT(logged_message == "[chn] - [TRACE] hello");
#else #else
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
#endif #endif
logged_message = null; logged_message = "none";
Log::Info("chn", test_msg); Log::Info("chn", test_msg);
#ifdef EMBB_DEBUG #ifdef EMBB_DEBUG
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [INFO ] hello")); PT_EXPECT(logged_message == "[chn] - [INFO ] hello");
#else #else
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
#endif #endif
logged_message = null; logged_message = "none";
Log::Warning("chn", test_msg); Log::Warning("chn", test_msg);
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [WARN ] hello")); PT_EXPECT(logged_message == "[chn] - [WARN ] hello");
logged_message = null; logged_message = "none";
Log::Error("chn", test_msg); Log::Error("chn", test_msg);
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [ERROR] hello")); PT_EXPECT(logged_message == "[chn] - [ERROR] hello");
Log::SetLogLevel(EMBB_LOG_LEVEL_INFO); Log::SetLogLevel(EMBB_LOG_LEVEL_INFO);
logged_message = null; logged_message = "none";
Log::Trace("chn", test_msg); Log::Trace("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Info("chn", test_msg); Log::Info("chn", test_msg);
#ifdef EMBB_DEBUG #ifdef EMBB_DEBUG
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [INFO ] hello")); PT_EXPECT(logged_message == "[chn] - [INFO ] hello");
#else #else
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
#endif #endif
logged_message = null; logged_message = "none";
Log::Warning("chn", test_msg); Log::Warning("chn", test_msg);
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [WARN ] hello")); PT_EXPECT(logged_message == "[chn] - [WARN ] hello");
logged_message = null; logged_message = "none";
Log::Error("chn", test_msg); Log::Error("chn", test_msg);
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [ERROR] hello")); PT_EXPECT(logged_message == "[chn] - [ERROR] hello");
Log::SetLogLevel(EMBB_LOG_LEVEL_WARNING); Log::SetLogLevel(EMBB_LOG_LEVEL_WARNING);
logged_message = null; logged_message = "none";
Log::Trace("chn", test_msg); Log::Trace("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Info("chn", test_msg); Log::Info("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Warning("chn", test_msg); Log::Warning("chn", test_msg);
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [WARN ] hello")); PT_EXPECT(logged_message == "[chn] - [WARN ] hello");
logged_message = null; logged_message = "none";
Log::Error("chn", test_msg); Log::Error("chn", test_msg);
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [ERROR] hello")); PT_EXPECT(logged_message == "[chn] - [ERROR] hello");
Log::SetLogLevel(EMBB_LOG_LEVEL_ERROR); Log::SetLogLevel(EMBB_LOG_LEVEL_ERROR);
logged_message = null; logged_message = "none";
Log::Trace("chn", test_msg); Log::Trace("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Info("chn", test_msg); Log::Info("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Warning("chn", test_msg); Log::Warning("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Error("chn", test_msg); Log::Error("chn", test_msg);
PT_EXPECT(0 == strcmp(logged_message, "[chn] - [ERROR] hello")); PT_EXPECT(logged_message == "[chn] - [ERROR] hello");
Log::SetLogLevel(EMBB_LOG_LEVEL_NONE); Log::SetLogLevel(EMBB_LOG_LEVEL_NONE);
logged_message = null; logged_message = "none";
Log::Trace("chn", test_msg); Log::Trace("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Info("chn", test_msg); Log::Info("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Warning("chn", test_msg); Log::Warning("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
logged_message = null; logged_message = "none";
Log::Error("chn", test_msg); Log::Error("chn", test_msg);
PT_EXPECT_EQ(null, logged_message); PT_EXPECT(logged_message == "none");
} }
} // namespace test } // namespace test
......
...@@ -123,8 +123,10 @@ bool LockFreeStack< Type, ValuePool >::TryPop(Type & element) { ...@@ -123,8 +123,10 @@ bool LockFreeStack< Type, ValuePool >::TryPop(Type & element) {
top_cached = top; top_cached = top;
// Stack empty, cannot pop // Stack empty, cannot pop
if (top_cached == NULL) if (top_cached == NULL) {
element = Type();
return false; return false;
}
// Guard top_cached // Guard top_cached
hazardPointer.Guard(0, top_cached); hazardPointer.Guard(0, top_cached);
......
...@@ -113,14 +113,17 @@ allocate_rec(int node, Type& element) { ...@@ -113,14 +113,17 @@ allocate_rec(int node, Type& element) {
int pool_index = NodeIndexToPoolIndex(node); int pool_index = NodeIndexToPoolIndex(node);
Type expected = pool_[pool_index]; Type expected = pool_[pool_index];
if (expected == Undefined) if (expected == Undefined) {
element = Type();
return -1; return -1;
}
if (pool_[pool_index].CompareAndSwap(expected, Undefined)) { if (pool_[pool_index].CompareAndSwap(expected, Undefined)) {
element = expected; element = expected;
return pool_index; return pool_index;
} }
element = Type();
return -1; return -1;
} }
...@@ -133,8 +136,10 @@ allocate_rec(int node, Type& element) { ...@@ -133,8 +136,10 @@ allocate_rec(int node, Type& element) {
do { do {
current = tree_[node]; current = tree_[node];
desired = current - 1; desired = current - 1;
if (desired < 0) if (desired < 0) {
element = Type();
return -1; return -1;
}
} while (!tree_[node].CompareAndSwap(current, desired)); } while (!tree_[node].CompareAndSwap(current, desired));
int leftResult = allocate_rec(GetLeftChildIndex(node), element); int leftResult = allocate_rec(GetLeftChildIndex(node), element);
......
...@@ -55,6 +55,7 @@ Allocate(Type & element) { ...@@ -55,6 +55,7 @@ Allocate(Type & element) {
return i; return i;
} }
} }
element = Type();
return -1; return -1;
} }
......
...@@ -144,6 +144,7 @@ void HazardPointerTest::HazardPointerTest1ThreadMethod() { ...@@ -144,6 +144,7 @@ void HazardPointerTest::HazardPointerTest1ThreadMethod() {
for (int i = 0; i != n_elements_per_thread_; ++i) { for (int i = 0; i != n_elements_per_thread_; ++i) {
embb::base::Atomic<int>* allocated_object = object_pool_->Allocate(0); embb::base::Atomic<int>* allocated_object = object_pool_->Allocate(0);
PT_ASSERT(NULL != allocated_object);
hazard_pointer_->Guard(0, allocated_object); hazard_pointer_->Guard(0, allocated_object);
...@@ -210,8 +211,9 @@ void HazardPointerTest2::DeletePointerCallback(int* to_delete) { ...@@ -210,8 +211,9 @@ void HazardPointerTest2::DeletePointerCallback(int* to_delete) {
} }
bool HazardPointerTest2::SetRelativeGuards() { bool HazardPointerTest2::SetRelativeGuards() {
unsigned int thread_index; unsigned int thread_index = 0;
embb_internal_thread_index(&thread_index); int result = embb_internal_thread_index(&thread_index);
PT_ASSERT(EMBB_SUCCESS == result);
unsigned int my_begin = guards_per_phread_count_*thread_index; unsigned int my_begin = guards_per_phread_count_*thread_index;
int guard_number = 0; int guard_number = 0;
...@@ -247,6 +249,7 @@ void HazardPointerTest2::HazardPointerTest2Master() { ...@@ -247,6 +249,7 @@ void HazardPointerTest2::HazardPointerTest2Master() {
// while the hazard pointer guard array is not full // while the hazard pointer guard array is not full
int** allocatedLocal = static_cast<int**>( int** allocatedLocal = static_cast<int**>(
embb::base::Allocation::Allocate(sizeof(int*)*guaranteed_capacity_pool_)); embb::base::Allocation::Allocate(sizeof(int*)*guaranteed_capacity_pool_));
PT_ASSERT(NULL != allocatedLocal);
bool full = false; bool full = false;
while (!full) { while (!full) {
...@@ -294,16 +297,19 @@ void HazardPointerTest2::HazardPointerTest2Pre() { ...@@ -294,16 +297,19 @@ void HazardPointerTest2::HazardPointerTest2Pre() {
// first the test pool has to be created // first the test pool has to be created
test_pool_ = embb::base::Allocation::New<IntObjectTestPool> test_pool_ = embb::base::Allocation::New<IntObjectTestPool>
(pool_size_using_hazard_pointer_); (pool_size_using_hazard_pointer_);
PT_ASSERT(NULL != test_pool_);
// after the pool has been created, we create the hp class // after the pool has been created, we create the hp class
hazard_pointer_ = embb::base::Allocation::New < hazard_pointer_ = embb::base::Allocation::New <
embb::containers::internal::HazardPointer<int*> > embb::containers::internal::HazardPointer<int*> >
(delete_pointer_callback_, static_cast<int*>(NULL), (delete_pointer_callback_, static_cast<int*>(NULL),
static_cast<int>(guards_per_phread_count_), n_threads); static_cast<int>(guards_per_phread_count_), n_threads);
PT_ASSERT(NULL != hazard_pointer_);
shared_guarded_ = static_cast<embb::base::Atomic<int*>*>( shared_guarded_ = static_cast<embb::base::Atomic<int*>*>(
embb::base::Allocation::Allocate(sizeof(embb::base::Atomic<int*>)* embb::base::Allocation::Allocate(sizeof(embb::base::Atomic<int*>)*
guaranteed_capacity_pool_)); guaranteed_capacity_pool_));
PT_ASSERT(NULL != shared_guarded_);
for (unsigned int i = 0; i != guaranteed_capacity_pool_; ++i) { for (unsigned int i = 0; i != guaranteed_capacity_pool_; ++i) {
// in-place new for each array cell // in-place new for each array cell
...@@ -450,8 +456,9 @@ void HazardPointerTest2::HazardPointerTest2Post() { ...@@ -450,8 +456,9 @@ void HazardPointerTest2::HazardPointerTest2Post() {
void HazardPointerTest2::HazardPointerTest2ThreadMethod() { void HazardPointerTest2::HazardPointerTest2ThreadMethod() {
for (;;) { for (;;) {
unsigned int thread_index; unsigned int thread_index = 0;
embb_internal_thread_index(&thread_index); int result = embb_internal_thread_index(&thread_index);
PT_ASSERT(EMBB_SUCCESS == result);
if (thread_index == current_master_) { if (thread_index == current_master_) {
HazardPointerTest2Master(); HazardPointerTest2Master();
......
...@@ -31,19 +31,11 @@ namespace embb { ...@@ -31,19 +31,11 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
class Scheduler;
class ClockListener;
struct InitData {
Scheduler * sched;
ClockListener * sink_listener;
};
class ClockListener { class ClockListener {
public: public:
virtual ~ClockListener() {} virtual ~ClockListener() {}
virtual void OnClock(int /*clock*/) = 0; virtual void OnClock(int /*clock*/) = 0;
virtual void OnInit(InitData * /*sched*/) = 0; virtual bool OnHasCycle(ClockListener * /*node*/) { return false; }
}; };
} // namespace internal } // namespace internal
......
...@@ -35,18 +35,21 @@ namespace embb { ...@@ -35,18 +35,21 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
template <int Slices, typename Type> template <typename Type>
class ConstantSource class ConstantSource
: public Node { : public Node {
public: public:
typedef Outputs<Slices, Type> OutputsType; typedef Outputs<Type> OutputsType;
private: private:
OutputsType outputs_; OutputsType outputs_;
Type value_; Type value_;
public: public:
explicit ConstantSource(Type value) : value_(value) {} ConstantSource(Scheduler * sched, Type value)
: value_(value) {
SetScheduler(sched);
}
virtual bool HasOutputs() const { virtual bool HasOutputs() const {
return outputs_.Size() > 0; return outputs_.Size() > 0;
...@@ -56,9 +59,8 @@ class ConstantSource ...@@ -56,9 +59,8 @@ class ConstantSource
GetOutput<0>().Send(Signal<Type>(clock, value_)); GetOutput<0>().Send(Signal<Type>(clock, value_));
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
SetScheduler(init_data->sched); return outputs_.IsFullyConnected();
GetOutput<0>().SendInit(init_data);
} }
virtual bool Start(int clock) { virtual bool Start(int clock) {
......
...@@ -41,54 +41,83 @@ namespace internal { ...@@ -41,54 +41,83 @@ namespace internal {
class Scheduler; class Scheduler;
template <typename, int> template <typename>
class Out; class Out;
template <typename Type, int Slices> template <typename Type>
class In { class In {
public: public:
typedef Signal<Type> SignalType; typedef Signal<Type> SignalType;
In() : connected_(false) {} In() : values_(NULL), connected_(false), slices_(0) {}
~In() {
if (NULL != values_) {
for (int ii = 0; ii < slices_; ii++) {
values_[ii].~SignalType();
}
embb::base::Allocation::Free(values_);
}
}
SignalType const & GetSignal(int clock) const { SignalType const & GetSignal(int clock) const {
return values_[clock % Slices]; return values_[clock % slices_];
} }
Type GetValue(int clock) const { Type GetValue(int clock) const {
SignalType const & signal = GetSignal(clock); SignalType const & signal = GetSignal(clock);
if (signal.IsBlank()) assert(!signal.IsBlank());
EMBB_THROW(embb::base::ErrorException,
"Signal is blank, cannot get a value.")
return signal.GetValue(); return signal.GetValue();
} }
bool IsConnected() const { return connected_; } bool IsConnected() const { return connected_; }
void SetConnected() { connected_ = true; } void SetConnected() { connected_ = true; }
bool HasCycle(ClockListener * node) {
return listener_->OnHasCycle(node);
}
void SetSlices(int slices) {
if (0 < slices_) {
for (int ii = 0; ii < slices_; ii++) {
values_[ii].~SignalType();
}
embb::base::Allocation::Free(values_);
values_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
values_ = reinterpret_cast<SignalType*>(
embb::base::Allocation::Allocate(
sizeof(SignalType)*slices_));
for (int ii = 0; ii < slices_; ii++) {
new (&values_[ii]) SignalType();
}
}
}
void SetListener(ClockListener * listener) { listener_ = listener; } void SetListener(ClockListener * listener) { listener_ = listener; }
void Clear(int clock) { void Clear(int clock) {
const int idx = clock % Slices; const int idx = clock % slices_;
values_[idx].Clear(); values_[idx].Clear();
} }
friend class Out<Type, Slices>; friend class Out<Type>;
private: private:
SignalType values_[Slices]; SignalType * values_;
ClockListener * listener_; ClockListener * listener_;
bool connected_; bool connected_;
int slices_;
#if EMBB_DATAFLOW_TRACE_SIGNAL_HISTORY #if EMBB_DATAFLOW_TRACE_SIGNAL_HISTORY
embb::base::Spinlock lock_; embb::base::Spinlock lock_;
std::vector<SignalType> history_; std::vector<SignalType> history_;
#endif #endif
void Receive(SignalType const & value) { void Receive(SignalType const & value) {
const int idx = value.GetClock() % Slices; const int idx = value.GetClock() % slices_;
if (values_[idx].GetClock() >= value.GetClock()) assert(values_[idx].GetClock() < value.GetClock());
EMBB_THROW(embb::base::ErrorException,
"Received signal does not increase clock.");
values_[idx] = value; values_[idx] = value;
listener_->OnClock(value.GetClock()); listener_->OnClock(value.GetClock());
#if EMBB_DATAFLOW_TRACE_SIGNAL_HISTORY #if EMBB_DATAFLOW_TRACE_SIGNAL_HISTORY
...@@ -97,10 +126,6 @@ class In { ...@@ -97,10 +126,6 @@ class In {
lock_.Unlock(); lock_.Unlock();
#endif #endif
} }
void ReceiveInit(InitData * init_data) {
listener_->OnInit(init_data);
}
}; };
} // namespace internal } // namespace internal
......
...@@ -36,7 +36,6 @@ namespace dataflow { ...@@ -36,7 +36,6 @@ namespace dataflow {
namespace internal { namespace internal {
template < template <
int,
typename = embb::base::internal::Nil, typename = embb::base::internal::Nil,
typename = embb::base::internal::Nil, typename = embb::base::internal::Nil,
typename = embb::base::internal::Nil, typename = embb::base::internal::Nil,
...@@ -44,8 +43,8 @@ template < ...@@ -44,8 +43,8 @@ template <
typename = embb::base::internal::Nil> typename = embb::base::internal::Nil>
class Inputs; class Inputs;
template <int Slices> template <>
class Inputs<Slices, embb::base::internal::Nil, embb::base::internal::Nil, class Inputs<embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil> embb::base::internal::Nil>
: public Tuple<embb::base::internal::Nil, embb::base::internal::Nil, : public Tuple<embb::base::internal::Nil, embb::base::internal::Nil,
...@@ -57,21 +56,43 @@ class Inputs<Slices, embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -57,21 +56,43 @@ class Inputs<Slices, embb::base::internal::Nil, embb::base::internal::Nil,
bool AreNoneBlank(int /*clock*/) { return false; } bool AreNoneBlank(int /*clock*/) { return false; }
bool AreAtClock(int /*clock*/) { return true; } bool AreAtClock(int /*clock*/) { return true; }
virtual void OnClock(int /*clock*/) {} virtual void OnClock(int /*clock*/) {}
virtual void OnInit(InitData * /*init_data*/) {} bool IsFullyConnected() {
return true;
}
void SetSlices(int /*slices*/) {}
}; };
template <int Slices, typename T1> template <typename T1>
class Inputs<Slices, T1, embb::base::internal::Nil, embb::base::internal::Nil, class Inputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> embb::base::internal::Nil, embb::base::internal::Nil>
: public Tuple<In<T1, Slices>, embb::base::internal::Nil, : public Tuple<In<T1>, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil> embb::base::internal::Nil>
, public ClockListener { , public ClockListener {
public: public:
Inputs() { Inputs() : count_(NULL), slices_(0) {
for (int ii = 0; ii < Slices; ii++) // empty
count_[ii] = 1; }
test_count_ = 1; void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 1;
}
}
this->template Get<0>().SetSlices(slices_);
}
~Inputs() {
if (NULL != count_) {
embb::base::Allocation::Free(count_);
}
} }
void SetListener(ClockListener * listener) { void SetListener(ClockListener * listener) {
listener_ = listener; listener_ = listener;
...@@ -89,38 +110,56 @@ class Inputs<Slices, T1, embb::base::internal::Nil, embb::base::internal::Nil, ...@@ -89,38 +110,56 @@ class Inputs<Slices, T1, embb::base::internal::Nil, embb::base::internal::Nil,
this->template Get<0>().Clear(clock); this->template Get<0>().Clear(clock);
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
const int idx = clock % Slices; const int idx = clock % slices_;
if (count_[idx] == 0) { assert(count_[idx] > 0);
EMBB_THROW(embb::base::ErrorException,
"All inputs already fired for this clock.");
}
if (--count_[idx] == 0) { if (--count_[idx] == 0) {
count_[idx] = 1; count_[idx] = 1;
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { virtual bool OnHasCycle(ClockListener * node) {
if (--test_count_ == 0) { return listener_->OnHasCycle(node);
listener_->OnInit(init_data); }
} bool IsFullyConnected() {
return this->template Get<0>().IsConnected();
} }
private: private:
embb::base::Atomic<int> count_[Slices]; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_;
}; };
template <int Slices, typename T1, typename T2> template <typename T1, typename T2>
class Inputs<Slices, T1, T2, embb::base::internal::Nil, class Inputs<T1, T2, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> embb::base::internal::Nil, embb::base::internal::Nil>
: public Tuple<In<T1, Slices>, In<T2, Slices>, embb::base::internal::Nil, : public Tuple<In<T1>, In<T2>, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> embb::base::internal::Nil, embb::base::internal::Nil>
, public ClockListener { , public ClockListener {
public: public:
Inputs() { Inputs() : count_(NULL), slices_(0) {
for (int ii = 0; ii < Slices; ii++) // empty
count_[ii] = 2; }
test_count_ = 2; void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 2;
}
}
this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_);
}
~Inputs() {
if (NULL != count_) {
embb::base::Allocation::Free(count_);
}
} }
void SetListener(ClockListener * listener) { void SetListener(ClockListener * listener) {
listener_ = listener; listener_ = listener;
...@@ -142,38 +181,58 @@ class Inputs<Slices, T1, T2, embb::base::internal::Nil, ...@@ -142,38 +181,58 @@ class Inputs<Slices, T1, T2, embb::base::internal::Nil,
this->template Get<1>().Clear(clock); this->template Get<1>().Clear(clock);
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
const int idx = clock % Slices; const int idx = clock % slices_;
if (count_[idx] == 0) { assert(count_[idx] > 0);
EMBB_THROW(embb::base::ErrorException,
"All inputs already fired for this clock.");
}
if (--count_[idx] == 0) { if (--count_[idx] == 0) {
count_[idx] = 2; count_[idx] = 2;
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { virtual bool OnHasCycle(ClockListener * node) {
if (--test_count_ == 0) { return listener_->OnHasCycle(node);
listener_->OnInit(init_data); }
} bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected();
} }
private: private:
embb::base::Atomic<int> count_[Slices]; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_;
}; };
template <int Slices, typename T1, typename T2, typename T3> template <typename T1, typename T2, typename T3>
class Inputs<Slices, T1, T2, T3, embb::base::internal::Nil, class Inputs<T1, T2, T3, embb::base::internal::Nil,
embb::base::internal::Nil> embb::base::internal::Nil>
: public Tuple<In<T1, Slices>, In<T2, Slices>, In<T3, Slices>, : public Tuple<In<T1>, In<T2>, In<T3>,
embb::base::internal::Nil, embb::base::internal::Nil> embb::base::internal::Nil, embb::base::internal::Nil>
, public ClockListener { , public ClockListener {
public: public:
Inputs() { Inputs() : count_(NULL), slices_(0) {
for (int ii = 0; ii < Slices; ii++) // empty
count_[ii] = 3; }
test_count_ = 3; void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 3;
}
}
this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_);
}
~Inputs() {
if (NULL != count_) {
embb::base::Allocation::Free(count_);
}
} }
void SetListener(ClockListener * listener) { void SetListener(ClockListener * listener) {
listener_ = listener; listener_ = listener;
...@@ -199,37 +258,59 @@ class Inputs<Slices, T1, T2, T3, embb::base::internal::Nil, ...@@ -199,37 +258,59 @@ class Inputs<Slices, T1, T2, T3, embb::base::internal::Nil,
this->template Get<2>().Clear(clock); this->template Get<2>().Clear(clock);
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
const int idx = clock % Slices; const int idx = clock % slices_;
if (count_[idx] == 0) { assert(count_[idx] > 0);
EMBB_THROW(embb::base::ErrorException,
"All inputs already fired for this clock.");
}
if (--count_[idx] == 0) { if (--count_[idx] == 0) {
count_[idx] = 3; count_[idx] = 3;
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { virtual bool OnHasCycle(ClockListener * node) {
if (--test_count_ == 0) { return listener_->OnHasCycle(node);
listener_->OnInit(init_data); }
} bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected() &
this->template Get<2>().IsConnected();
} }
private: private:
embb::base::Atomic<int> count_[Slices]; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_;
}; };
template <int Slices, typename T1, typename T2, typename T3, typename T4> template <typename T1, typename T2, typename T3, typename T4>
class Inputs<Slices, T1, T2, T3, T4, embb::base::internal::Nil> class Inputs<T1, T2, T3, T4, embb::base::internal::Nil>
: public Tuple<In<T1, Slices>, In<T2, Slices>, In<T3, Slices>, : public Tuple<In<T1>, In<T2>, In<T3>,
In<T4, Slices>, embb::base::internal::Nil> In<T4>, embb::base::internal::Nil>
, public ClockListener { , public ClockListener {
public: public:
Inputs() { Inputs() : count_(NULL), slices_(0) {
for (int ii = 0; ii < Slices; ii++) // empty
count_[ii] = 4; }
test_count_ = 4; void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 4;
}
}
this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_);
this->template Get<3>().SetSlices(slices_);
}
~Inputs() {
if (NULL != count_) {
embb::base::Allocation::Free(count_);
}
} }
void SetListener(ClockListener * listener) { void SetListener(ClockListener * listener) {
listener_ = listener; listener_ = listener;
...@@ -259,38 +340,62 @@ class Inputs<Slices, T1, T2, T3, T4, embb::base::internal::Nil> ...@@ -259,38 +340,62 @@ class Inputs<Slices, T1, T2, T3, T4, embb::base::internal::Nil>
this->template Get<3>().Clear(clock); this->template Get<3>().Clear(clock);
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
const int idx = clock % Slices; const int idx = clock % slices_;
if (count_[idx] == 0) { assert(count_[idx] > 0);
EMBB_THROW(embb::base::ErrorException,
"All inputs already fired for this clock.");
}
if (--count_[idx] == 0) { if (--count_[idx] == 0) {
count_[idx] = 4; count_[idx] = 4;
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { virtual bool OnHasCycle(ClockListener * node) {
if (--test_count_ == 0) { return listener_->OnHasCycle(node);
listener_->OnInit(init_data); }
} bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &
this->template Get<1>().IsConnected() &
this->template Get<2>().IsConnected() &
this->template Get<3>().IsConnected();
} }
private: private:
embb::base::Atomic<int> count_[Slices]; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_;
}; };
template <int Slices, typename T1, typename T2, typename T3, typename T4, template <typename T1, typename T2, typename T3, typename T4,
typename T5> typename T5>
class Inputs class Inputs
: public Tuple<In<T1, Slices>, In<T2, Slices>, In<T3, Slices>, : public Tuple<In<T1>, In<T2>, In<T3>,
In<T4, Slices>, In<T5, Slices> > In<T4>, In<T5> >
, public ClockListener { , public ClockListener {
public: public:
Inputs() { Inputs() : count_(NULL), slices_(0) {
for (int ii = 0; ii < Slices; ii++) // empty
count_[ii] = 5; }
test_count_ = 5; void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(count_);
count_ = NULL;
}
slices_ = slices;
if (0 < slices_) {
count_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
count_[ii] = 5;
}
}
this->template Get<0>().SetSlices(slices_);
this->template Get<1>().SetSlices(slices_);
this->template Get<2>().SetSlices(slices_);
this->template Get<3>().SetSlices(slices_);
this->template Get<4>().SetSlices(slices_);
}
~Inputs() {
if (NULL != count_) {
embb::base::Allocation::Free(count_);
}
} }
void SetListener(ClockListener * listener) { void SetListener(ClockListener * listener) {
listener_ = listener; listener_ = listener;
...@@ -324,25 +429,27 @@ class Inputs ...@@ -324,25 +429,27 @@ class Inputs
this->template Get<4>().Clear(clock); this->template Get<4>().Clear(clock);
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
const int idx = clock % Slices; const int idx = clock % slices_;
if (count_[idx] == 0) { assert(count_[idx] > 0);
EMBB_THROW(embb::base::ErrorException,
"All inputs already fired for this clock.");
}
if (--count_[idx] == 0) { if (--count_[idx] == 0) {
count_[idx] = 5; count_[idx] = 5;
listener_->OnClock(clock); listener_->OnClock(clock);
} }
} }
virtual void OnInit(InitData * init_data) { virtual bool OnHasCycle(ClockListener * node) {
if (--test_count_ == 0) { return listener_->OnHasCycle(node);
listener_->OnInit(init_data); }
} bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected() &
this->template Get<2>().IsConnected() &
this->template Get<3>().IsConnected() &
this->template Get<4>().IsConnected();
} }
private: private:
embb::base::Atomic<int> count_[Slices]; embb::base::Atomic<int> * count_;
int test_count_;
ClockListener * listener_; ClockListener * listener_;
int slices_;
}; };
} // namespace internal } // namespace internal
......
...@@ -43,18 +43,28 @@ class Node { ...@@ -43,18 +43,28 @@ class Node {
virtual bool HasInputs() const { return false; } virtual bool HasInputs() const { return false; }
virtual bool HasOutputs() const { return false; } virtual bool HasOutputs() const { return false; }
virtual void Run(int clock) = 0; virtual void Run(int clock) = 0;
virtual bool IsFullyConnected() = 0;
virtual bool IsSequential() { return true; }
virtual bool HasCycle() { return false; }
virtual bool Start(int /*clock*/) { virtual bool Start(int /*clock*/) {
EMBB_THROW(embb::base::ErrorException, EMBB_THROW(embb::base::ErrorException,
"Nodes are started implicitly."); "Nodes are started implicitly.");
} }
virtual void Init(InitData * init_data) = 0; void SetScheduler(Scheduler * sched) {
sched_ = sched;
if (NULL != sched_) {
SetSlices(sched_->GetSlices());
} else {
SetSlices(0);
}
}
protected: protected:
Scheduler * sched_; Scheduler * sched_;
static int next_process_id_; static int next_process_id_;
void SetScheduler(Scheduler * sched) { sched_ = sched; }
static int GetNextProcessID() { return next_process_id_++; } static int GetNextProcessID() { return next_process_id_++; }
virtual void SetSlices(int /*slices*/) {}
}; };
} // namespace internal } // namespace internal
......
...@@ -36,12 +36,13 @@ namespace dataflow { ...@@ -36,12 +36,13 @@ namespace dataflow {
namespace internal { namespace internal {
class Scheduler; class Scheduler;
class ClockListener;
template <typename Type, int Slices> template <typename Type>
class Out { class Out {
public: public:
typedef Signal<Type> SignalType; typedef Signal<Type> SignalType;
typedef In<Type, Slices> InType; typedef In<Type> InType;
Out() { Out() {
} }
...@@ -52,12 +53,6 @@ class Out { ...@@ -52,12 +53,6 @@ class Out {
} }
} }
void SendInit(InitData * init_data) {
for (size_t ii = 0; ii < targets_.size(); ii++) {
targets_[ii]->ReceiveInit(init_data);
}
}
void Connect(InType & input) { void Connect(InType & input) {
if (input.IsConnected()) { if (input.IsConnected()) {
EMBB_THROW(embb::base::ErrorException, EMBB_THROW(embb::base::ErrorException,
...@@ -72,6 +67,18 @@ class Out { ...@@ -72,6 +67,18 @@ class Out {
Connect(input); Connect(input);
} }
bool IsConnected() const {
return targets_.size() > 0;
}
bool HasCycle(ClockListener * node) {
bool result = false;
for (size_t ii = 0; ii < targets_.size() && !result; ii++) {
result = result || targets_[ii]->HasCycle(node);
}
return result;
}
private: private:
std::vector< InType * > targets_; std::vector< InType * > targets_;
}; };
......
...@@ -35,7 +35,6 @@ namespace dataflow { ...@@ -35,7 +35,6 @@ namespace dataflow {
namespace internal { namespace internal {
template < template <
int,
typename = embb::base::internal::Nil, typename = embb::base::internal::Nil,
typename = embb::base::internal::Nil, typename = embb::base::internal::Nil,
typename = embb::base::internal::Nil, typename = embb::base::internal::Nil,
...@@ -43,54 +42,112 @@ template < ...@@ -43,54 +42,112 @@ template <
typename = embb::base::internal::Nil > typename = embb::base::internal::Nil >
class Outputs; class Outputs;
template <int Slices> class ClockListener;
class Outputs<Slices, embb::base::internal::Nil, embb::base::internal::Nil,
template <>
class Outputs<embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil> embb::base::internal::Nil>
: public Tuple<embb::base::internal::Nil, embb::base::internal::Nil, : public Tuple<embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil> { embb::base::internal::Nil> {
public: public:
bool IsFullyConnected() {
return true;
}
bool HasCycle(ClockListener * /*node*/) {
return false;
}
}; };
template <int Slices, typename T1> template <typename T1>
class Outputs<Slices, T1, embb::base::internal::Nil, embb::base::internal::Nil, class Outputs<T1, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> embb::base::internal::Nil, embb::base::internal::Nil>
: public Tuple<Out<T1, Slices>, embb::base::internal::Nil, : public Tuple<Out<T1>, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil, embb::base::internal::Nil,
embb::base::internal::Nil> { embb::base::internal::Nil> {
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node);
}
}; };
template <int Slices, typename T1, typename T2> template <typename T1, typename T2>
class Outputs<Slices, T1, T2, embb::base::internal::Nil, class Outputs<T1, T2, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> embb::base::internal::Nil, embb::base::internal::Nil>
: public Tuple<Out<T1, Slices>, Out<T2, Slices>, embb::base::internal::Nil, : public Tuple<Out<T1>, Out<T2>, embb::base::internal::Nil,
embb::base::internal::Nil, embb::base::internal::Nil> { embb::base::internal::Nil, embb::base::internal::Nil> {
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node);
}
}; };
template <int Slices, typename T1, typename T2, typename T3> template <typename T1, typename T2, typename T3>
class Outputs<Slices, T1, T2, T3, embb::base::internal::Nil, class Outputs<T1, T2, T3, embb::base::internal::Nil,
embb::base::internal::Nil> embb::base::internal::Nil>
: public Tuple<Out<T1, Slices>, Out<T2, Slices>, Out<T3, Slices>, : public Tuple<Out<T1>, Out<T2>, Out<T3>,
embb::base::internal::Nil, embb::base::internal::Nil> { embb::base::internal::Nil, embb::base::internal::Nil> {
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected() &&
this->template Get<2>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node) ||
this->template Get<2>().HasCycle(node);
}
}; };
template <int Slices, typename T1, typename T2, typename T3, typename T4> template <typename T1, typename T2, typename T3, typename T4>
class Outputs<Slices, T1, T2, T3, T4, embb::base::internal::Nil> class Outputs<T1, T2, T3, T4, embb::base::internal::Nil>
: public Tuple<Out<T1, Slices>, Out<T2, Slices>, Out<T3, Slices>, : public Tuple<Out<T1>, Out<T2>, Out<T3>,
Out<T4, Slices>, embb::base::internal::Nil>{ Out<T4>, embb::base::internal::Nil>{
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected() &&
this->template Get<2>().IsConnected() &&
this->template Get<3>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node) ||
this->template Get<2>().HasCycle(node) ||
this->template Get<3>().HasCycle(node);
}
}; };
template <int Slices, typename T1, typename T2, typename T3, typename T4, template <typename T1, typename T2, typename T3, typename T4,
typename T5> typename T5>
class Outputs class Outputs
: public Tuple<Out<T1, Slices>, Out<T2, Slices>, Out<T3, Slices>, : public Tuple<Out<T1>, Out<T2>, Out<T3>,
Out<T4, Slices>, Out<T5, Slices> > { Out<T4>, Out<T5> > {
public: public:
bool IsFullyConnected() {
return this->template Get<0>().IsConnected() &&
this->template Get<1>().IsConnected() &&
this->template Get<2>().IsConnected() &&
this->template Get<3>().IsConnected() &&
this->template Get<4>().IsConnected();
}
bool HasCycle(ClockListener * node) {
return this->template Get<0>().HasCycle(node) ||
this->template Get<1>().HasCycle(node) ||
this->template Get<2>().HasCycle(node) ||
this->template Get<3>().HasCycle(node) ||
this->template Get<4>().HasCycle(node);
}
}; };
} // namespace internal } // namespace internal
......
...@@ -37,24 +37,27 @@ namespace embb { ...@@ -37,24 +37,27 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
template <int Slices, bool Serial, class INPUTS, class OUTPUTS> class Process; template <bool Serial, class INPUTS, class OUTPUTS> class Process;
template < template <
int Slices, bool Serial, bool Serial,
typename I1, typename I2, typename I3, typename I4, typename I5, typename I1, typename I2, typename I3, typename I4, typename I5,
typename O1, typename O2, typename O3, typename O4, typename O5> typename O1, typename O2, typename O3, typename O4, typename O5>
class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
Outputs<Slices, O1, O2, O3, O4, O5> > Outputs<O1, O2, O3, O4, O5> >
: public Node : public Node
, public ClockListener { , public ClockListener {
public: public:
typedef Inputs<Slices, I1, I2, I3, I4, I5> InputsType; typedef Inputs<I1, I2, I3, I4, I5> InputsType;
typedef Outputs<Slices, O1, O2, O3, O4, O5> OutputsType; typedef Outputs<O1, O2, O3, O4, O5> OutputsType;
typedef ProcessExecutor< InputsType, OutputsType > ExecutorType; typedef ProcessExecutor< InputsType, OutputsType > ExecutorType;
typedef typename ExecutorType::FunctionType FunctionType; typedef typename ExecutorType::FunctionType FunctionType;
explicit Process(FunctionType function) Process(Scheduler * sched, FunctionType function)
: executor_(function) { : inputs_()
, executor_(function)
, action_(NULL)
, slices_(0) {
next_clock_ = 0; next_clock_ = 0;
queued_clock_ = 0; queued_clock_ = 0;
bool ordered = Serial; bool ordered = Serial;
...@@ -64,6 +67,13 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, ...@@ -64,6 +67,13 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>,
queue_id_ = 0; queue_id_ = 0;
} }
inputs_.SetListener(this); inputs_.SetListener(this);
SetScheduler(sched);
}
~Process() {
if (NULL != action_) {
embb::base::Allocation::Free(action_);
}
} }
virtual bool HasInputs() const { virtual bool HasInputs() const {
...@@ -78,9 +88,16 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, ...@@ -78,9 +88,16 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>,
executor_.Execute(clock, inputs_, outputs_); executor_.Execute(clock, inputs_, outputs_);
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
SetScheduler(init_data->sched); return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
executor_.Init(init_data, outputs_); }
virtual bool IsSequential() {
return Serial;
}
virtual bool HasCycle() {
return outputs_.HasCycle(this);
} }
InputsType & GetInputs() { InputsType & GetInputs() {
...@@ -108,17 +125,14 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, ...@@ -108,17 +125,14 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>,
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
if (!inputs_.AreAtClock(clock)) { assert(inputs_.AreAtClock(clock));
EMBB_THROW(embb::base::ErrorException,
"Some inputs are not at expected clock.")
}
bool ordered = Serial; bool ordered = Serial;
if (ordered) { if (ordered) {
bool retry = true; bool retry = true;
while (retry) { while (retry) {
int clk = next_clock_; int clk = next_clock_;
int clk_end = clk + Slices; int clk_end = clk + slices_;
int clk_res = clk; int clk_res = clk;
for (int ii = clk; ii < clk_end; ii++) { for (int ii = clk; ii < clk_end; ii++) {
if (!inputs_.AreAtClock(ii)) { if (!inputs_.AreAtClock(ii)) {
...@@ -130,7 +144,7 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, ...@@ -130,7 +144,7 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>,
if (next_clock_.CompareAndSwap(clk, clk_res)) { if (next_clock_.CompareAndSwap(clk, clk_res)) {
while (queued_clock_.Load() < clk) continue; while (queued_clock_.Load() < clk) continue;
for (int ii = clk; ii < clk_res; ii++) { for (int ii = clk; ii < clk_res; ii++) {
const int idx = ii % Slices; const int idx = ii % slices_;
action_[idx] = Action(this, ii); action_[idx] = Action(this, ii);
sched_->Enqueue(queue_id_, action_[idx]); sched_->Enqueue(queue_id_, action_[idx]);
} }
...@@ -142,24 +156,47 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, ...@@ -142,24 +156,47 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>,
} }
} }
} else { } else {
const int idx = clock % Slices; const int idx = clock % slices_;
action_[idx] = Action(this, clock); action_[idx] = Action(this, clock);
sched_->Spawn(action_[idx]); sched_->Spawn(action_[idx]);
} }
} }
virtual void OnInit(InitData * init_data) { virtual bool OnHasCycle(ClockListener * node) {
Init(init_data); ClockListener * this_node = this;
if (this_node == node) {
return true;
} else {
return outputs_.HasCycle(node);
}
} }
private: private:
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
ExecutorType executor_; ExecutorType executor_;
Action action_[Slices]; Action * action_;
embb::base::Atomic<int> next_clock_; embb::base::Atomic<int> next_clock_;
embb::base::Atomic<int> queued_clock_; embb::base::Atomic<int> queued_clock_;
int queue_id_; int queue_id_;
int slices_;
virtual void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(action_);
action_ = NULL;
}
slices_ = slices;
inputs_.SetSlices(slices);
if (0 < slices_) {
action_ = reinterpret_cast<Action*>(
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
}
}
}; };
} // namespace internal } // namespace internal
......
...@@ -40,8 +40,8 @@ namespace internal { ...@@ -40,8 +40,8 @@ namespace internal {
template <class Inputs, class Outputs> template <class Inputs, class Outputs>
class ProcessExecutor; class ProcessExecutor;
template <int Slices, typename I1, typename O1> template <typename I1, typename O1>
class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1> > { class ProcessExecutor< Inputs<I1>, Outputs<O1> > {
public: public:
typedef embb::base::Function<void, I1 const &, O1 &> FunctionType; typedef embb::base::Function<void, I1 const &, O1 &> FunctionType;
...@@ -49,8 +49,8 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1> > { ...@@ -49,8 +49,8 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1> & inputs, Inputs<I1> & inputs,
Outputs<Slices, O1> & outputs) { Outputs<O1> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
function_( function_(
...@@ -62,16 +62,12 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1> > { ...@@ -62,16 +62,12 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename O1, typename O2> template <typename I1, typename O1, typename O2>
class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2> > { class ProcessExecutor< Inputs<I1>, Outputs<O1, O2> > {
public: public:
typedef embb::base::Function<void, I1 const &, O1 &, O2 &> FunctionType; typedef embb::base::Function<void, I1 const &, O1 &, O2 &> FunctionType;
...@@ -79,8 +75,8 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2> > { ...@@ -79,8 +75,8 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1> & inputs, Inputs<I1> & inputs,
Outputs<Slices, O1, O2> & outputs) { Outputs<O1, O2> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
O2 o2; O2 o2;
...@@ -95,17 +91,12 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2> > { ...@@ -95,17 +91,12 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename O1, typename O2, typename O3> template <typename I1, typename O1, typename O2, typename O3>
class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3> > { class ProcessExecutor< Inputs<I1>, Outputs<O1, O2, O3> > {
public: public:
typedef embb::base::Function<void, I1 const &, O1 &, O2 &, O3 &> typedef embb::base::Function<void, I1 const &, O1 &, O2 &, O3 &>
FunctionType; FunctionType;
...@@ -114,8 +105,8 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3> > { ...@@ -114,8 +105,8 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1> & inputs, Inputs<I1> & inputs,
Outputs<Slices, O1, O2, O3> & outputs) { Outputs<O1, O2, O3> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
O2 o2; O2 o2;
...@@ -133,19 +124,13 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3> > { ...@@ -133,19 +124,13 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2, O3> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename O1, typename O2, typename O3, template <typename I1, typename O1, typename O2, typename O3,
typename O4> typename O4>
class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3, O4> > { class ProcessExecutor< Inputs<I1>, Outputs<O1, O2, O3, O4> > {
public: public:
typedef embb::base::Function<void, I1 const &, O1 &, O2 &, O3 &, O4 &> typedef embb::base::Function<void, I1 const &, O1 &, O2 &, O3 &, O4 &>
FunctionType; FunctionType;
...@@ -154,8 +139,8 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3, O4> > { ...@@ -154,8 +139,8 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3, O4> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1> & inputs, Inputs<I1> & inputs,
Outputs<Slices, O1, O2, O3, O4> & outputs) { Outputs<O1, O2, O3, O4> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
O2 o2; O2 o2;
...@@ -176,19 +161,12 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3, O4> > { ...@@ -176,19 +161,12 @@ class ProcessExecutor< Inputs<Slices, I1>, Outputs<Slices, O1, O2, O3, O4> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2, O3, O4> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
outputs.template Get<3>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename O1> template <typename I1, typename I2, typename O1>
class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1> > { class ProcessExecutor< Inputs<I1, I2>, Outputs<O1> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, O1 &> typedef embb::base::Function<void, I1 const &, I2 const &, O1 &>
FunctionType; FunctionType;
...@@ -197,8 +175,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1> > { ...@@ -197,8 +175,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2> & inputs, Inputs<I1, I2> & inputs,
Outputs<Slices, O1> & outputs) { Outputs<O1> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
function_( function_(
...@@ -211,16 +189,12 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1> > { ...@@ -211,16 +189,12 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename O1, typename O2> template <typename I1, typename I2, typename O1, typename O2>
class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2> > { class ProcessExecutor< Inputs<I1, I2>, Outputs<O1, O2> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, O1 &, O2 &> typedef embb::base::Function<void, I1 const &, I2 const &, O1 &, O2 &>
FunctionType; FunctionType;
...@@ -229,8 +203,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2> > { ...@@ -229,8 +203,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2> & inputs, Inputs<I1, I2> & inputs,
Outputs<Slices, O1, O2> & outputs) { Outputs<O1, O2> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
O2 o2; O2 o2;
...@@ -246,18 +220,13 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2> > { ...@@ -246,18 +220,13 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename O1, typename O2, template <typename I1, typename I2, typename O1, typename O2,
typename O3> typename O3>
class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2, O3> > { class ProcessExecutor< Inputs<I1, I2>, Outputs<O1, O2, O3> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, O1 &, O2 &, O3 &> typedef embb::base::Function<void, I1 const &, I2 const &, O1 &, O2 &, O3 &>
FunctionType; FunctionType;
...@@ -266,8 +235,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2, O3> > { ...@@ -266,8 +235,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2, O3> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2> & inputs, Inputs<I1, I2> & inputs,
Outputs<Slices, O1, O2, O3> & outputs) { Outputs<O1, O2, O3> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
O2 o2; O2 o2;
...@@ -286,18 +255,12 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2, O3> > { ...@@ -286,18 +255,12 @@ class ProcessExecutor< Inputs<Slices, I1, I2>, Outputs<Slices, O1, O2, O3> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2, O3> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename I3, typename O1> template <typename I1, typename I2, typename I3, typename O1>
class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1> > { class ProcessExecutor< Inputs<I1, I2, I3>, Outputs<O1> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &, O1 &> typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &, O1 &>
FunctionType; FunctionType;
...@@ -306,8 +269,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1> > { ...@@ -306,8 +269,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2, I3> & inputs, Inputs<I1, I2, I3> & inputs,
Outputs<Slices, O1> & outputs) { Outputs<O1> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
function_( function_(
...@@ -321,17 +284,13 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1> > { ...@@ -321,17 +284,13 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename I3, typename O1, template <typename I1, typename I2, typename I3, typename O1,
typename O2> typename O2>
class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1, O2> > { class ProcessExecutor< Inputs<I1, I2, I3>, Outputs<O1, O2> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &, typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &,
O1 &, O2 &> FunctionType; O1 &, O2 &> FunctionType;
...@@ -340,8 +299,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1, O2> > { ...@@ -340,8 +299,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1, O2> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2, I3> & inputs, Inputs<I1, I2, I3> & inputs,
Outputs<Slices, O1, O2> & outputs) { Outputs<O1, O2> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
O2 o2; O2 o2;
...@@ -358,18 +317,13 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1, O2> > { ...@@ -358,18 +317,13 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3>, Outputs<Slices, O1, O2> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename I3, typename I4, template <typename I1, typename I2, typename I3, typename I4,
typename O1> typename O1>
class ProcessExecutor< Inputs<Slices, I1, I2, I3, I4>, Outputs<Slices, O1> > { class ProcessExecutor< Inputs<I1, I2, I3, I4>, Outputs<O1> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &, typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &,
I4 const &, O1 &> FunctionType; I4 const &, O1 &> FunctionType;
...@@ -378,8 +332,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3, I4>, Outputs<Slices, O1> > { ...@@ -378,8 +332,8 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3, I4>, Outputs<Slices, O1> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2, I3, I4> & inputs, Inputs<I1, I2, I3, I4> & inputs,
Outputs<Slices, O1> & outputs) { Outputs<O1> & outputs) {
if (inputs.AreNoneBlank(clock)) { if (inputs.AreNoneBlank(clock)) {
O1 o1; O1 o1;
function_( function_(
...@@ -394,10 +348,6 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3, I4>, Outputs<Slices, O1> > { ...@@ -394,10 +348,6 @@ class ProcessExecutor< Inputs<Slices, I1, I2, I3, I4>, Outputs<Slices, O1> > {
} }
} }
void Init(InitData * init_data, Outputs<Slices, O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
......
...@@ -40,6 +40,7 @@ class Scheduler { ...@@ -40,6 +40,7 @@ class Scheduler {
virtual void Spawn(Action & action) = 0; virtual void Spawn(Action & action) = 0;
virtual void Enqueue(int process_id, Action & action) = 0; virtual void Enqueue(int process_id, Action & action) = 0;
virtual void WaitForSlice(int slice) = 0; virtual void WaitForSlice(int slice) = 0;
virtual int GetSlices() = 0;
}; };
} // namespace internal } // namespace internal
......
...@@ -38,12 +38,24 @@ namespace embb { ...@@ -38,12 +38,24 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
template <int Slices>
class SchedulerMTAPI : public Scheduler { class SchedulerMTAPI : public Scheduler {
public: public:
SchedulerMTAPI() { explicit SchedulerMTAPI(int slices)
: slices_(slices) {
embb::tasks::Node & node = embb::tasks::Node::GetInstance(); embb::tasks::Node & node = embb::tasks::Node::GetInstance();
for (int ii = 0; ii < Slices; ii++) {
int tl = std::min(
static_cast<int>(node.GetTaskLimit()),
static_cast<int>(node.GetGroupCount()));
if (tl < slices_) {
slices_ = tl;
}
group_ = reinterpret_cast<embb::tasks::Group**>(
embb::base::Allocation::Allocate(
sizeof(embb::tasks::Group*)*slices_));
for (int ii = 0; ii < slices_; ii++) {
embb::tasks::Group & group = node.CreateGroup(); embb::tasks::Group & group = node.CreateGroup();
group_[ii] = &group; group_[ii] = &group;
} }
...@@ -61,22 +73,26 @@ class SchedulerMTAPI : public Scheduler { ...@@ -61,22 +73,26 @@ class SchedulerMTAPI : public Scheduler {
} }
} }
virtual ~SchedulerMTAPI() { virtual ~SchedulerMTAPI() {
embb::tasks::Node & node = embb::tasks::Node::GetInstance(); if (embb::tasks::Node::IsInitialized()) {
for (int ii = 0; ii < Slices; ii++) { // only destroy groups and queues if there still is an instance
group_[ii]->WaitAll(MTAPI_INFINITE); embb::tasks::Node & node = embb::tasks::Node::GetInstance();
node.DestroyGroup(*group_[ii]); for (int ii = 0; ii < slices_; ii++) {
} group_[ii]->WaitAll(MTAPI_INFINITE);
for (int ii = 0; ii < queue_count_; ii++) { node.DestroyGroup(*group_[ii]);
node.DestroyQueue(*queue_[ii]); }
for (int ii = 0; ii < queue_count_; ii++) {
node.DestroyQueue(*queue_[ii]);
}
} }
embb::base::Allocation::Free(group_);
embb::base::Allocation::Free(queue_); embb::base::Allocation::Free(queue_);
} }
virtual void Spawn(Action & action) { virtual void Spawn(Action & action) {
const int idx = action.GetClock() % Slices; const int idx = action.GetClock() % slices_;
group_[idx]->Spawn(embb::base::MakeFunction(action, &Action::RunMTAPI)); group_[idx]->Spawn(embb::base::MakeFunction(action, &Action::RunMTAPI));
} }
virtual void Enqueue(int process_id, Action & action) { virtual void Enqueue(int process_id, Action & action) {
const int idx = action.GetClock() % Slices; const int idx = action.GetClock() % slices_;
const int queue_id = process_id % queue_count_; const int queue_id = process_id % queue_count_;
queue_[queue_id]->Spawn(group_[idx], queue_[queue_id]->Spawn(group_[idx],
embb::base::MakeFunction(action, &Action::RunMTAPI)); embb::base::MakeFunction(action, &Action::RunMTAPI));
...@@ -84,11 +100,13 @@ class SchedulerMTAPI : public Scheduler { ...@@ -84,11 +100,13 @@ class SchedulerMTAPI : public Scheduler {
virtual void WaitForSlice(int slice) { virtual void WaitForSlice(int slice) {
group_[slice]->WaitAll(MTAPI_INFINITE); group_[slice]->WaitAll(MTAPI_INFINITE);
} }
virtual int GetSlices() { return slices_; }
private: private:
embb::tasks::Group * group_[Slices]; embb::tasks::Group ** group_;
embb::tasks::Queue ** queue_; embb::tasks::Queue ** queue_;
int queue_count_; int queue_count_;
int slices_;
}; };
} // namespace internal } // namespace internal
......
...@@ -45,6 +45,7 @@ class SchedulerSequential : public Scheduler { ...@@ -45,6 +45,7 @@ class SchedulerSequential : public Scheduler {
action.RunSequential(); action.RunSequential();
} }
virtual void WaitForSlice(int /*slice*/) {} virtual void WaitForSlice(int /*slice*/) {}
virtual int GetSlices() { return 1; }
}; };
} // namespace internal } // namespace internal
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#ifndef EMBB_DATAFLOW_INTERNAL_SELECT_H_ #ifndef EMBB_DATAFLOW_INTERNAL_SELECT_H_
#define EMBB_DATAFLOW_INTERNAL_SELECT_H_ #define EMBB_DATAFLOW_INTERNAL_SELECT_H_
#include <embb/dataflow/internal/action.h>
#include <embb/dataflow/internal/signal.h> #include <embb/dataflow/internal/signal.h>
#include <embb/dataflow/internal/node.h> #include <embb/dataflow/internal/node.h>
#include <embb/dataflow/internal/inputs.h> #include <embb/dataflow/internal/inputs.h>
...@@ -37,16 +36,17 @@ namespace embb { ...@@ -37,16 +36,17 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
template <int Slices, typename Type> template <typename Type>
class Select class Select
: public Node : public Node
, public ClockListener { , public ClockListener {
public: public:
typedef Inputs<Slices, bool, Type, Type> InputsType; typedef Inputs<bool, Type, Type> InputsType;
typedef Outputs<Slices, Type> OutputsType; typedef Outputs<Type> OutputsType;
Select() { explicit Select(Scheduler * sched) : inputs_(), slices_(0) {
inputs_.SetListener(this); inputs_.SetListener(this);
SetScheduler(sched);
} }
virtual bool HasInputs() const { virtual bool HasInputs() const {
...@@ -81,9 +81,17 @@ class Select ...@@ -81,9 +81,17 @@ class Select
} }
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
SetScheduler(init_data->sched); return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
GetOutput<0>().SendInit(init_data); }
virtual bool OnHasCycle(ClockListener * node) {
ClockListener * this_node = this;
if (this_node == node) {
return true;
} else {
return outputs_.HasCycle(node);
}
} }
InputsType & GetInputs() { InputsType & GetInputs() {
...@@ -112,20 +120,19 @@ class Select ...@@ -112,20 +120,19 @@ class Select
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
//const int idx = clock % Slices; //const int idx = clock % Slices;
if (!inputs_.AreAtClock(clock)) assert(inputs_.AreAtClock(clock));
EMBB_THROW(embb::base::ErrorException,
"Some inputs are not at expected clock.")
Run(clock); Run(clock);
} }
virtual void OnInit(InitData * init_data) {
Init(init_data);
}
private: private:
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
Action action_[Slices]; int slices_;
virtual void SetSlices(int slices) {
slices_ = slices;
inputs_.SetSlices(slices);
}
}; };
} // namespace internal } // namespace internal
......
...@@ -36,29 +36,36 @@ namespace embb { ...@@ -36,29 +36,36 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
template <int Slices, class Inputs> class Sink; template <class Inputs> class Sink;
template < template <
int Slices,
typename I1, typename I2, typename I3, typename I4, typename I5> typename I1, typename I2, typename I3, typename I4, typename I5>
class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> > class Sink< Inputs<I1, I2, I3, I4, I5> >
: public Node : public Node
, public ClockListener { , public ClockListener {
public: public:
typedef Inputs<Slices, I1, I2, I3, I4, I5> InputsType; typedef Inputs<I1, I2, I3, I4, I5> InputsType;
typedef SinkExecutor< InputsType > ExecutorType; typedef SinkExecutor< InputsType > ExecutorType;
typedef typename ExecutorType::FunctionType FunctionType; typedef typename ExecutorType::FunctionType FunctionType;
explicit Sink(FunctionType function) Sink(Scheduler * sched, ClockListener * listener,
: executor_(function) { FunctionType function)
: inputs_()
, executor_(function)
, action_(NULL)
, slices_(0) {
next_clock_ = 0; next_clock_ = 0;
queued_clock_ = 0; queued_clock_ = 0;
queue_id_ = GetNextProcessID(); queue_id_ = GetNextProcessID();
inputs_.SetListener(this); inputs_.SetListener(this);
listener_ = listener;
SetScheduler(sched);
} }
void SetListener(ClockListener * listener) { ~Sink() {
listener_ = listener; if (NULL != action_) {
embb::base::Allocation::Free(action_);
}
} }
virtual bool HasInputs() const { virtual bool HasInputs() const {
...@@ -72,10 +79,8 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> > ...@@ -72,10 +79,8 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> >
listener_->OnClock(clock); listener_->OnClock(clock);
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
SetListener(init_data->sink_listener); return inputs_.IsFullyConnected();
SetScheduler(init_data->sched);
listener_->OnInit(init_data);
} }
InputsType & GetInputs() { InputsType & GetInputs() {
...@@ -88,15 +93,13 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> > ...@@ -88,15 +93,13 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> >
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
if (!inputs_.AreAtClock(clock)) { EMBB_UNUSED_IN_RELEASE(clock);
EMBB_THROW(embb::base::ErrorException, assert(inputs_.AreAtClock(clock));
"Some inputs are not at expected clock.")
}
bool retry = true; bool retry = true;
while (retry) { while (retry) {
int clk = next_clock_; int clk = next_clock_;
int clk_end = clk + Slices; int clk_end = clk + slices_;
int clk_res = clk; int clk_res = clk;
for (int ii = clk; ii < clk_end; ii++) { for (int ii = clk; ii < clk_end; ii++) {
if (!inputs_.AreAtClock(ii)) { if (!inputs_.AreAtClock(ii)) {
...@@ -108,7 +111,7 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> > ...@@ -108,7 +111,7 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> >
if (next_clock_.CompareAndSwap(clk, clk_res)) { if (next_clock_.CompareAndSwap(clk, clk_res)) {
while (queued_clock_.Load() < clk) continue; while (queued_clock_.Load() < clk) continue;
for (int ii = clk; ii < clk_res; ii++) { for (int ii = clk; ii < clk_res; ii++) {
const int idx = ii % Slices; const int idx = ii % slices_;
action_[idx] = Action(this, ii); action_[idx] = Action(this, ii);
sched_->Enqueue(queue_id_, action_[idx]); sched_->Enqueue(queue_id_, action_[idx]);
} }
...@@ -121,18 +124,32 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> > ...@@ -121,18 +124,32 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> >
} }
} }
virtual void OnInit(InitData * init_data) {
Init(init_data);
}
private: private:
InputsType inputs_; InputsType inputs_;
ExecutorType executor_; ExecutorType executor_;
Action action_[Slices]; Action * action_;
ClockListener * listener_; ClockListener * listener_;
embb::base::Atomic<int> next_clock_; embb::base::Atomic<int> next_clock_;
embb::base::Atomic<int> queued_clock_; embb::base::Atomic<int> queued_clock_;
int queue_id_; int queue_id_;
int slices_;
virtual void SetSlices(int slices) {
if (0 < slices_) {
embb::base::Allocation::Free(action_);
action_ = NULL;
}
slices_ = slices;
inputs_.SetSlices(slices);
if (0 < slices_) {
action_ = reinterpret_cast<Action*>(
embb::base::Allocation::Allocate(
sizeof(Action)*slices_));
for (int ii = 0; ii < slices_; ii++) {
action_[ii] = Action();
}
}
}
}; };
} // namespace internal } // namespace internal
......
...@@ -38,8 +38,8 @@ namespace internal { ...@@ -38,8 +38,8 @@ namespace internal {
template <class Inputs> template <class Inputs>
class SinkExecutor; class SinkExecutor;
template <int Slices, typename I1> template <typename I1>
class SinkExecutor< Inputs<Slices, I1> > { class SinkExecutor< Inputs<I1> > {
public: public:
typedef embb::base::Function<void, I1 const &> FunctionType; typedef embb::base::Function<void, I1 const &> FunctionType;
...@@ -47,7 +47,7 @@ class SinkExecutor< Inputs<Slices, I1> > { ...@@ -47,7 +47,7 @@ class SinkExecutor< Inputs<Slices, I1> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1> & inputs) { Inputs<I1> & inputs) {
function_( function_(
inputs.template Get<0>().GetValue(clock)); inputs.template Get<0>().GetValue(clock));
} }
...@@ -56,8 +56,8 @@ class SinkExecutor< Inputs<Slices, I1> > { ...@@ -56,8 +56,8 @@ class SinkExecutor< Inputs<Slices, I1> > {
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2> template <typename I1, typename I2>
class SinkExecutor< Inputs<Slices, I1, I2> > { class SinkExecutor< Inputs<I1, I2> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &> FunctionType; typedef embb::base::Function<void, I1 const &, I2 const &> FunctionType;
...@@ -65,7 +65,7 @@ class SinkExecutor< Inputs<Slices, I1, I2> > { ...@@ -65,7 +65,7 @@ class SinkExecutor< Inputs<Slices, I1, I2> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2> & inputs) { Inputs<I1, I2> & inputs) {
function_( function_(
inputs.template Get<0>().GetValue(clock), inputs.template Get<0>().GetValue(clock),
inputs.template Get<1>().GetValue(clock)); inputs.template Get<1>().GetValue(clock));
...@@ -75,8 +75,8 @@ class SinkExecutor< Inputs<Slices, I1, I2> > { ...@@ -75,8 +75,8 @@ class SinkExecutor< Inputs<Slices, I1, I2> > {
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename I3> template <typename I1, typename I2, typename I3>
class SinkExecutor< Inputs<Slices, I1, I2, I3> > { class SinkExecutor< Inputs<I1, I2, I3> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &> typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &>
FunctionType; FunctionType;
...@@ -85,7 +85,7 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3> > { ...@@ -85,7 +85,7 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2, I3> & inputs) { Inputs<I1, I2, I3> & inputs) {
function_( function_(
inputs.template Get<0>().GetValue(clock), inputs.template Get<0>().GetValue(clock),
inputs.template Get<1>().GetValue(clock), inputs.template Get<1>().GetValue(clock),
...@@ -96,8 +96,8 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3> > { ...@@ -96,8 +96,8 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3> > {
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename I3, typename I4> template <typename I1, typename I2, typename I3, typename I4>
class SinkExecutor< Inputs<Slices, I1, I2, I3, I4> > { class SinkExecutor< Inputs<I1, I2, I3, I4> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &, typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &,
I4 const &> FunctionType; I4 const &> FunctionType;
...@@ -106,7 +106,7 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3, I4> > { ...@@ -106,7 +106,7 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3, I4> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2, I3, I4> & inputs) { Inputs<I1, I2, I3, I4> & inputs) {
function_( function_(
inputs.template Get<0>().GetValue(clock), inputs.template Get<0>().GetValue(clock),
inputs.template Get<1>().GetValue(clock), inputs.template Get<1>().GetValue(clock),
...@@ -118,9 +118,9 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3, I4> > { ...@@ -118,9 +118,9 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3, I4> > {
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename I1, typename I2, typename I3, typename I4, template <typename I1, typename I2, typename I3, typename I4,
typename I5> typename I5>
class SinkExecutor< Inputs<Slices, I1, I2, I3, I4, I5> > { class SinkExecutor< Inputs<I1, I2, I3, I4, I5> > {
public: public:
typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &, typedef embb::base::Function<void, I1 const &, I2 const &, I3 const &,
I4 const &, I5 const &> FunctionType; I4 const &, I5 const &> FunctionType;
...@@ -129,7 +129,7 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3, I4, I5> > { ...@@ -129,7 +129,7 @@ class SinkExecutor< Inputs<Slices, I1, I2, I3, I4, I5> > {
void Execute( void Execute(
int clock, int clock,
Inputs<Slices, I1, I2, I3, I4, I5> & inputs) { Inputs<I1, I2, I3, I4, I5> & inputs) {
function_( function_(
inputs.template Get<0>().GetValue(clock), inputs.template Get<0>().GetValue(clock),
inputs.template Get<1>().GetValue(clock), inputs.template Get<1>().GetValue(clock),
......
...@@ -37,20 +37,20 @@ namespace embb { ...@@ -37,20 +37,20 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
template <int Slices, class Outputs> class Source; template <class Outputs> class Source;
template < template <
int Slices,
typename O1, typename O2, typename O3, typename O4, typename O5> typename O1, typename O2, typename O3, typename O4, typename O5>
class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> > class Source< Outputs<O1, O2, O3, O4, O5> >
: public Node { : public Node {
public: public:
typedef Outputs<Slices, O1, O2, O3, O4, O5> OutputsType; typedef Outputs<O1, O2, O3, O4, O5> OutputsType;
typedef SourceExecutor< OutputsType > ExecutorType; typedef SourceExecutor< OutputsType > ExecutorType;
typedef typename ExecutorType::FunctionType FunctionType; typedef typename ExecutorType::FunctionType FunctionType;
explicit Source(FunctionType function) Source(Scheduler * sched, FunctionType function)
: executor_(function), not_done_(true) { : executor_(function), not_done_(true) {
SetScheduler(sched);
} }
virtual bool HasOutputs() const { virtual bool HasOutputs() const {
...@@ -61,9 +61,8 @@ class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> > ...@@ -61,9 +61,8 @@ class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> >
not_done_ = executor_.Execute(clock, outputs_); not_done_ = executor_.Execute(clock, outputs_);
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
SetScheduler(init_data->sched); return outputs_.IsFullyConnected();
executor_.Init(init_data, outputs_);
} }
virtual bool Start(int clock) { virtual bool Start(int clock) {
......
...@@ -36,13 +36,11 @@ namespace embb { ...@@ -36,13 +36,11 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
class Scheduler;
template <class OUTPUTS> template <class OUTPUTS>
class SourceExecutor; class SourceExecutor;
template <int Slices, typename O1> template <typename O1>
class SourceExecutor< Outputs<Slices, O1> > { class SourceExecutor< Outputs<O1> > {
public: public:
typedef embb::base::Function<bool, O1 &> FunctionType; typedef embb::base::Function<bool, O1 &> FunctionType;
...@@ -50,7 +48,7 @@ class SourceExecutor< Outputs<Slices, O1> > { ...@@ -50,7 +48,7 @@ class SourceExecutor< Outputs<Slices, O1> > {
bool Execute( bool Execute(
int clock, int clock,
Outputs<Slices, O1> & outputs) { Outputs<O1> & outputs) {
O1 o1; O1 o1;
bool result = function_(o1); bool result = function_(o1);
if (result) { if (result) {
...@@ -59,16 +57,12 @@ class SourceExecutor< Outputs<Slices, O1> > { ...@@ -59,16 +57,12 @@ class SourceExecutor< Outputs<Slices, O1> > {
return result; return result;
} }
void Init(InitData * init_data, Outputs<Slices, O1> & outputs) {
outputs.template Get<0>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename O1, typename O2> template <typename O1, typename O2>
class SourceExecutor< Outputs<Slices, O1, O2> > { class SourceExecutor< Outputs<O1, O2> > {
public: public:
typedef embb::base::Function<bool, O1 &, O2 &> FunctionType; typedef embb::base::Function<bool, O1 &, O2 &> FunctionType;
...@@ -76,7 +70,7 @@ class SourceExecutor< Outputs<Slices, O1, O2> > { ...@@ -76,7 +70,7 @@ class SourceExecutor< Outputs<Slices, O1, O2> > {
bool Execute( bool Execute(
int clock, int clock,
Outputs<Slices, O1, O2> & outputs) { Outputs<O1, O2> & outputs) {
O1 o1; O1 o1;
O2 o2; O2 o2;
bool result = function_(o1, o2); bool result = function_(o1, o2);
...@@ -87,17 +81,12 @@ class SourceExecutor< Outputs<Slices, O1, O2> > { ...@@ -87,17 +81,12 @@ class SourceExecutor< Outputs<Slices, O1, O2> > {
return result; return result;
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename O1, typename O2, typename O3> template <typename O1, typename O2, typename O3>
class SourceExecutor< Outputs<Slices, O1, O2, O3> > { class SourceExecutor< Outputs<O1, O2, O3> > {
public: public:
typedef embb::base::Function<bool, O1 &, O2 &, O3 &> FunctionType; typedef embb::base::Function<bool, O1 &, O2 &, O3 &> FunctionType;
...@@ -105,7 +94,7 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3> > { ...@@ -105,7 +94,7 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3> > {
bool Execute( bool Execute(
int clock, int clock,
Outputs<Slices, O1, O2, O3> & outputs) { Outputs<O1, O2, O3> & outputs) {
O1 o1; O1 o1;
O2 o2; O2 o2;
O3 o3; O3 o3;
...@@ -118,18 +107,12 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3> > { ...@@ -118,18 +107,12 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3> > {
return result; return result;
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2, O3> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename O1, typename O2, typename O3, typename O4> template <typename O1, typename O2, typename O3, typename O4>
class SourceExecutor< Outputs<Slices, O1, O2, O3, O4> > { class SourceExecutor< Outputs<O1, O2, O3, O4> > {
public: public:
typedef embb::base::Function<bool, O1 &, O2 &, O3 &, O4 &> FunctionType; typedef embb::base::Function<bool, O1 &, O2 &, O3 &, O4 &> FunctionType;
...@@ -137,7 +120,7 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3, O4> > { ...@@ -137,7 +120,7 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3, O4> > {
bool Execute( bool Execute(
int clock, int clock,
Outputs<Slices, O1, O2, O3, O4> & outputs) { Outputs<O1, O2, O3, O4> & outputs) {
O1 o1; O1 o1;
O2 o2; O2 o2;
O3 o3; O3 o3;
...@@ -152,20 +135,13 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3, O4> > { ...@@ -152,20 +135,13 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3, O4> > {
return result; return result;
} }
void Init(InitData * init_data, Outputs<Slices, O1, O2, O3, O4> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
outputs.template Get<3>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
template <int Slices, typename O1, typename O2, typename O3, typename O4, template <typename O1, typename O2, typename O3, typename O4,
typename O5> typename O5>
class SourceExecutor< Outputs<Slices, O1, O2, O3, O4, O5> > { class SourceExecutor< Outputs<O1, O2, O3, O4, O5> > {
public: public:
typedef embb::base::Function<bool, O1 &, O2 &, O3 &, O4 &, O5 &> FunctionType; typedef embb::base::Function<bool, O1 &, O2 &, O3 &, O4 &, O5 &> FunctionType;
...@@ -173,7 +149,7 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3, O4, O5> > { ...@@ -173,7 +149,7 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3, O4, O5> > {
bool Execute( bool Execute(
int clock, int clock,
Outputs<Slices, O1, O2, O3, O4, O5> & outputs) { Outputs<O1, O2, O3, O4, O5> & outputs) {
O1 o1; O1 o1;
O2 o2; O2 o2;
O3 o3; O3 o3;
...@@ -190,15 +166,6 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3, O4, O5> > { ...@@ -190,15 +166,6 @@ class SourceExecutor< Outputs<Slices, O1, O2, O3, O4, O5> > {
return result; return result;
} }
void Init(
InitData * init_data, Outputs<Slices, O1, O2, O3, O4, O5> & outputs) {
outputs.template Get<0>().SendInit(init_data);
outputs.template Get<1>().SendInit(init_data);
outputs.template Get<2>().SendInit(init_data);
outputs.template Get<3>().SendInit(init_data);
outputs.template Get<4>().SendInit(init_data);
}
private: private:
FunctionType function_; FunctionType function_;
}; };
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#ifndef EMBB_DATAFLOW_INTERNAL_SWITCH_H_ #ifndef EMBB_DATAFLOW_INTERNAL_SWITCH_H_
#define EMBB_DATAFLOW_INTERNAL_SWITCH_H_ #define EMBB_DATAFLOW_INTERNAL_SWITCH_H_
#include <embb/dataflow/internal/action.h>
#include <embb/dataflow/internal/signal.h> #include <embb/dataflow/internal/signal.h>
#include <embb/dataflow/internal/node.h> #include <embb/dataflow/internal/node.h>
#include <embb/dataflow/internal/inputs.h> #include <embb/dataflow/internal/inputs.h>
...@@ -37,16 +36,17 @@ namespace embb { ...@@ -37,16 +36,17 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
template <int Slices, typename Type> template <typename Type>
class Switch class Switch
: public Node : public Node
, public ClockListener { , public ClockListener {
public: public:
typedef Inputs<Slices, bool, Type> InputsType; typedef Inputs<bool, Type> InputsType;
typedef Outputs<Slices, Type, Type> OutputsType; typedef Outputs<Type, Type> OutputsType;
Switch() { explicit Switch(Scheduler * sched) : inputs_() {
inputs_.SetListener(this); inputs_.SetListener(this);
SetScheduler(sched);
} }
virtual bool HasInputs() const { virtual bool HasInputs() const {
...@@ -78,10 +78,17 @@ class Switch ...@@ -78,10 +78,17 @@ class Switch
} }
} }
virtual void Init(InitData * init_data) { virtual bool IsFullyConnected() {
SetScheduler(init_data->sched); return inputs_.IsFullyConnected() && outputs_.IsFullyConnected();
GetOutput<0>().SendInit(init_data); }
GetOutput<1>().SendInit(init_data);
virtual bool OnHasCycle(ClockListener * node) {
ClockListener * this_node = this;
if (this_node == node) {
return true;
} else {
return outputs_.HasCycle(node);
}
} }
InputsType & GetInputs() { InputsType & GetInputs() {
...@@ -110,20 +117,17 @@ class Switch ...@@ -110,20 +117,17 @@ class Switch
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
//const int idx = clock % Slices; //const int idx = clock % Slices;
if (!inputs_.AreAtClock(clock)) assert(inputs_.AreAtClock(clock));
EMBB_THROW(embb::base::ErrorException,
"Some inputs are not at expected clock.")
Run(clock); Run(clock);
} }
virtual void OnInit(InitData * init_data) {
Init(init_data);
}
private: private:
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
Action action_[Slices];
virtual void SetSlices(int slices) {
inputs_.SetSlices(slices);
}
}; };
} // namespace internal } // namespace internal
......
...@@ -52,18 +52,25 @@ namespace dataflow { ...@@ -52,18 +52,25 @@ namespace dataflow {
/** /**
* Represents a set of processes, that are connected by communication channels. * Represents a set of processes, that are connected by communication channels.
* *
* \tparam Slices Number of concurrently processed tokens.
* \ingroup CPP_DATAFLOW * \ingroup CPP_DATAFLOW
*/ */
template <int Slices>
class Network { class Network {
public: public:
/** /**
* Constructs an empty network. * Constructs an empty network.
* \note The number of concurrent tokens will automatically be derived from
* the structure of the network on the first call to operator(), and the
* corresponding resources will be allocated then.
*/ */
Network() {} Network() {}
/** /**
* Constructs an empty network.
* \param slices Number of concurrent tokens allowed in the network.
*/
explicit Network(int slices) {}
/**
* Input port class. * Input port class.
*/ */
template <typename Type> template <typename Type>
...@@ -198,9 +205,10 @@ class Network { ...@@ -198,9 +205,10 @@ class Network {
/** /**
* Constructs a SerialProcess with a user specified processing function. * Constructs a SerialProcess with a user specified processing function.
* \param network The network this node is going to be part of.
* \param function The Function to call to process a token. * \param function The Function to call to process a token.
*/ */
explicit SerialProcess(FunctionType function); explicit SerialProcess(Network & network, FunctionType function);
/** /**
* \returns \c true if the SerialProcess has any inputs, \c false * \returns \c true if the SerialProcess has any inputs, \c false
...@@ -279,9 +287,10 @@ class Network { ...@@ -279,9 +287,10 @@ class Network {
/** /**
* Constructs a ParallelProcess with a user specified processing function. * Constructs a ParallelProcess with a user specified processing function.
* \param network The network this node is going to be part of.
* \param function The Function to call to process a token. * \param function The Function to call to process a token.
*/ */
explicit ParallelProcess(FunctionType function); explicit ParallelProcess(Network & network, FunctionType function);
/** /**
* \returns \c true if the ParallelProcess has any inputs, \c false * \returns \c true if the ParallelProcess has any inputs, \c false
...@@ -341,6 +350,7 @@ class Network { ...@@ -341,6 +350,7 @@ class Network {
*/ */
template<typename Type> template<typename Type>
class Switch { class Switch {
public:
/** /**
* Function type to use when processing tokens. * Function type to use when processing tokens.
*/ */
...@@ -357,6 +367,12 @@ class Network { ...@@ -357,6 +367,12 @@ class Network {
typedef Outputs<Type> OutputsType; typedef Outputs<Type> OutputsType;
/** /**
* Constructs a Switch process.
* \param network The network this node is going to be part of.
*/
explicit Select(Network & network);
/**
* \returns Always \c true. * \returns Always \c true.
*/ */
virtual bool HasInputs() const; virtual bool HasInputs() const;
...@@ -412,6 +428,7 @@ class Network { ...@@ -412,6 +428,7 @@ class Network {
*/ */
template<typename Type> template<typename Type>
class Select { class Select {
public:
/** /**
* Function type to use when processing tokens. * Function type to use when processing tokens.
*/ */
...@@ -428,6 +445,12 @@ class Network { ...@@ -428,6 +445,12 @@ class Network {
typedef Outputs<Type> OutputsType; typedef Outputs<Type> OutputsType;
/** /**
* Constructs a Select process.
* \param network The network this node is going to be part of.
*/
explicit Select(Network & network);
/**
* \returns Always \c true. * \returns Always \c true.
*/ */
virtual bool HasInputs() const; virtual bool HasInputs() const;
...@@ -502,9 +525,10 @@ class Network { ...@@ -502,9 +525,10 @@ class Network {
/** /**
* Constructs a Sink with a user specified processing function. * Constructs a Sink with a user specified processing function.
* \param network The network this node is going to be part of.
* \param function The Function to call to process a token. * \param function The Function to call to process a token.
*/ */
explicit Sink(FunctionType function); explicit Sink(Network & network, FunctionType function);
/** /**
* \returns Always \c true. * \returns Always \c true.
...@@ -561,9 +585,10 @@ class Network { ...@@ -561,9 +585,10 @@ class Network {
/** /**
* Constructs a Source with a user specified processing function. * Constructs a Source with a user specified processing function.
* \param network The network this node is going to be part of.
* \param function The Function to call to emit a token. * \param function The Function to call to emit a token.
*/ */
explicit Source(FunctionType function); explicit Source(Network & network, FunctionType function);
/** /**
* \returns Always \c false. * \returns Always \c false.
...@@ -596,13 +621,6 @@ class Network { ...@@ -596,13 +621,6 @@ class Network {
}; };
/** /**
* Adds a new source process to the network.
* \param source The source process to add.
*/
template<typename O1, typename O2, typename O3, typename O4, typename O5>
void AddSource(Source<O1, O2, O3, O4, O5> & source);
/**
* Constant source process template. * Constant source process template.
* *
* A constant source has one output port and emits a constant value given * A constant source has one output port and emits a constant value given
...@@ -620,9 +638,10 @@ class Network { ...@@ -620,9 +638,10 @@ class Network {
/** /**
* Constructs a ConstantSource with a value to emit on each token. * Constructs a ConstantSource with a value to emit on each token.
* \param network The network this node is going to be part of.
* \param value The value to emit. * \param value The value to emit.
*/ */
explicit ConstantSource(Type value); explicit ConstantSource(Network & network, Type value);
/** /**
* \returns Always \c false. * \returns Always \c false.
...@@ -655,39 +674,66 @@ class Network { ...@@ -655,39 +674,66 @@ class Network {
}; };
/** /**
* Adds a new constant source process to the network. * Checks whether the network is completely connected and free of cycles.
* \param source The constant source process to add. * \returns \c true if everything is in order, \c false if not.
* \note Executing an invalid network results in an exception. For this
* reason, it is recommended to first check the network using IsValid().
*/ */
template<typename Type> bool IsValid();
void AddSource(ConstantSource<Type> & source);
/** /**
* Executes the network until one of the the sources returns \c false. * Executes the network until one of the the sources returns \c false.
* \note If the network was default constructed, the number of concurrent
* tokens will automatically be derived from the structure of the network
* on the first call of the operator, and the corresponding resources will
* be allocated then.
* \note Executing an invalid network results in an exception. For this
* reason, it is recommended to first check the network using IsValid().
*/ */
void operator () (); void operator () ();
}; };
#else #else
template <int Slices>
class Network : public internal::ClockListener { class Network : public internal::ClockListener {
public: public:
Network() {} Network()
: sink_counter_(NULL), sink_count_(0), slices_(0), sched_(NULL) {
// empty
}
template <typename T1, typename T2 = embb::base::internal::Nil, explicit Network(int slices)
: sink_counter_(NULL), sink_count_(0), slices_(slices), sched_(NULL) {
PrepareSlices();
}
~Network() {
if (NULL != sched_) {
embb::base::Allocation::Delete(sched_);
sched_ = NULL;
}
if (NULL != sink_counter_) {
embb::base::Allocation::Free(sink_counter_);
sink_counter_ = NULL;
}
}
template <typename T1,
typename T2 = embb::base::internal::Nil,
typename T3 = embb::base::internal::Nil, typename T3 = embb::base::internal::Nil,
typename T4 = embb::base::internal::Nil, typename T4 = embb::base::internal::Nil,
typename T5 = embb::base::internal::Nil> typename T5 = embb::base::internal::Nil>
struct Inputs { class Inputs {
typedef internal::Inputs<Slices, T1, T2, T3, T4, T5> Type; // empty
}; };
template <typename T1, typename T2 = embb::base::internal::Nil, template <typename T1,
typename T2 = embb::base::internal::Nil,
typename T3 = embb::base::internal::Nil, typename T3 = embb::base::internal::Nil,
typename T4 = embb::base::internal::Nil, typename T4 = embb::base::internal::Nil,
typename T5 = embb::base::internal::Nil> typename T5 = embb::base::internal::Nil>
struct Outputs { class Outputs {
typedef internal::Outputs<Slices, T1, T2, T3, T4, T5> Type; // empty
}; };
template <class Inputs, class Outputs> class SerialProcess; template <class Inputs, class Outputs> class SerialProcess;
...@@ -695,21 +741,22 @@ class Network : public internal::ClockListener { ...@@ -695,21 +741,22 @@ class Network : public internal::ClockListener {
template < template <
typename I1, typename I2, typename I3, typename I4, typename I5, typename I1, typename I2, typename I3, typename I4, typename I5,
typename O1, typename O2, typename O3, typename O4, typename O5> typename O1, typename O2, typename O3, typename O4, typename O5>
class SerialProcess< internal::Inputs<Slices, I1, I2, I3, I4, I5>, class SerialProcess< Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<Slices, O1, O2, O3, O4, O5> > Outputs<O1, O2, O3, O4, O5> >
: public internal::Process< Slices, true, : public internal::Process< true,
internal::Inputs<Slices, I1, I2, I3, I4, I5>, internal::Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<Slices, O1, O2, O3, O4, O5> > { internal::Outputs<O1, O2, O3, O4, O5> > {
public: public:
typedef typename internal::Process< Slices, true, typedef typename internal::Process< true,
internal::Inputs<Slices, I1, I2, I3, I4, I5>, internal::Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<Slices, O1, O2, O3, O4, O5> >::FunctionType internal::Outputs<O1, O2, O3, O4, O5> >::FunctionType
FunctionType; FunctionType;
explicit SerialProcess(FunctionType function) explicit SerialProcess(Network & network, FunctionType function)
: internal::Process< Slices, true, : internal::Process< true,
internal::Inputs<Slices, I1, I2, I3, I4, I5>, internal::Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<Slices, O1, O2, O3, O4, O5> >(function) { internal::Outputs<O1, O2, O3, O4, O5> >(
//empty network.sched_, function) {
network.processes_.push_back(this);
} }
}; };
...@@ -718,48 +765,59 @@ class Network : public internal::ClockListener { ...@@ -718,48 +765,59 @@ class Network : public internal::ClockListener {
template < template <
typename I1, typename I2, typename I3, typename I4, typename I5, typename I1, typename I2, typename I3, typename I4, typename I5,
typename O1, typename O2, typename O3, typename O4, typename O5> typename O1, typename O2, typename O3, typename O4, typename O5>
class ParallelProcess< internal::Inputs<Slices, I1, I2, I3, I4, I5>, class ParallelProcess< Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<Slices, O1, O2, O3, O4, O5> > Outputs<O1, O2, O3, O4, O5> >
: public internal::Process< Slices, false, : public internal::Process< false,
internal::Inputs<Slices, I1, I2, I3, I4, I5>, internal::Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<Slices, O1, O2, O3, O4, O5> >{ internal::Outputs<O1, O2, O3, O4, O5> >{
public: public:
typedef typename internal::Process< Slices, false, typedef typename internal::Process< false,
internal::Inputs<Slices, I1, I2, I3, I4, I5>, internal::Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<Slices, O1, O2, O3, O4, O5> >::FunctionType internal::Outputs<O1, O2, O3, O4, O5> >::FunctionType
FunctionType; FunctionType;
explicit ParallelProcess(FunctionType function) explicit ParallelProcess(Network & network, FunctionType function)
: internal::Process< Slices, false, : internal::Process< false,
internal::Inputs<Slices, I1, I2, I3, I4, I5>, internal::Inputs<I1, I2, I3, I4, I5>,
internal::Outputs<Slices, O1, O2, O3, O4, O5> >(function) { internal::Outputs<O1, O2, O3, O4, O5> >(
//empty network.sched_, function) {
network.processes_.push_back(this);
} }
}; };
template<typename Type> template<typename Type>
class Switch : public internal::Switch<Slices, Type> { class Switch : public internal::Switch<Type> {
public: public:
explicit Switch(Network & network)
: internal::Switch<Type>(network.sched_) {
network.processes_.push_back(this);
}
}; };
template<typename Type> template<typename Type>
class Select : public internal::Select<Slices, Type> { class Select : public internal::Select<Type> {
public: public:
explicit Select(Network & network)
: internal::Select<Type>(network.sched_) {
network.processes_.push_back(this);
}
}; };
template<typename I1, typename I2 = embb::base::internal::Nil, template<typename I1, typename I2 = embb::base::internal::Nil,
typename I3 = embb::base::internal::Nil, typename I3 = embb::base::internal::Nil,
typename I4 = embb::base::internal::Nil, typename I4 = embb::base::internal::Nil,
typename I5 = embb::base::internal::Nil> typename I5 = embb::base::internal::Nil>
class Sink : public internal::Sink<Slices, class Sink : public internal::Sink<
internal::Inputs<Slices, I1, I2, I3, I4, I5> > { internal::Inputs<I1, I2, I3, I4, I5> > {
public: public:
typedef typename internal::Sink<Slices, typedef typename internal::Sink<
internal::Inputs<Slices, I1, I2, I3, I4, I5> >::FunctionType FunctionType; internal::Inputs<I1, I2, I3, I4, I5> >::FunctionType FunctionType;
explicit Sink(FunctionType function) explicit Sink(Network & network, FunctionType function)
: internal::Sink<Slices, : internal::Sink<
internal::Inputs<Slices, I1, I2, I3, I4, I5> >(function) { internal::Inputs<I1, I2, I3, I4, I5> >(
//empty network.sched_, &network, function) {
network.sinks_.push_back(this);
network.sink_count_++;
} }
}; };
...@@ -767,70 +825,86 @@ class Network : public internal::ClockListener { ...@@ -767,70 +825,86 @@ class Network : public internal::ClockListener {
typename O3 = embb::base::internal::Nil, typename O3 = embb::base::internal::Nil,
typename O4 = embb::base::internal::Nil, typename O4 = embb::base::internal::Nil,
typename O5 = embb::base::internal::Nil> typename O5 = embb::base::internal::Nil>
class Source : public internal::Source<Slices, class Source : public internal::Source<
internal::Outputs<Slices, O1, O2, O3, O4, O5> > { internal::Outputs<O1, O2, O3, O4, O5> > {
public: public:
typedef typename internal::Source<Slices, typedef typename internal::Source<
internal::Outputs<Slices, O1, O2, O3, O4, O5> >::FunctionType internal::Outputs<O1, O2, O3, O4, O5> >::FunctionType
FunctionType; FunctionType;
explicit Source(FunctionType function) explicit Source(Network & network, FunctionType function)
: internal::Source<Slices, : internal::Source<
internal::Outputs<Slices, O1, O2, O3, O4, O5> >(function) { internal::Outputs<O1, O2, O3, O4, O5> >(network.sched_, function) {
//empty network.sources_.push_back(this);
} }
}; };
template<typename O1, typename O2, typename O3, typename O4, typename O5>
void AddSource(Source<O1, O2, O3, O4, O5> & source) {
sources_.push_back(&source);
}
template<typename Type> template<typename Type>
class ConstantSource : public internal::ConstantSource<Slices, Type> { class ConstantSource : public internal::ConstantSource<Type> {
public: public:
explicit ConstantSource(Type value) explicit ConstantSource(Network & network, Type value)
: internal::ConstantSource<Slices, Type>(value) { : internal::ConstantSource<Type>(network.sched_, value) {
//empty network.sources_.push_back(this);
} }
}; };
template<typename Type> bool IsValid() {
void AddSource(ConstantSource<Type> & source) { bool valid = true;
sources_.push_back(&source); // check connectivity
for (size_t ii = 0; ii < sources_.size() && valid; ii++) {
valid = valid && sources_[ii]->IsFullyConnected();
}
for (size_t ii = 0; ii < processes_.size() && valid; ii++) {
valid = valid && processes_[ii]->IsFullyConnected();
}
for (size_t ii = 0; ii < sinks_.size() && valid; ii++) {
valid = valid && sinks_[ii]->IsFullyConnected();
}
// check for cycles
for (size_t ii = 0; ii < processes_.size() && valid; ii++) {
valid = valid && !processes_[ii]->HasCycle();
}
return valid;
} }
void operator () () { void operator () () {
internal::SchedulerSequential sched_seq; if (0 >= slices_) {
internal::SchedulerMTAPI<Slices> sched_mtapi; slices_ = static_cast<int>(
internal::Scheduler * sched = &sched_mtapi; sources_.size() +
sinks_.size());
internal::InitData init_data; for (size_t ii = 0; ii < processes_.size(); ii++) {
init_data.sched = sched; int tt = processes_[ii]->IsSequential() ? 1 :
init_data.sink_listener = this; static_cast<int>(embb_core_count_available());
slices_ += tt;
sink_count_ = 0; }
for (size_t it = 0; it < sources_.size(); it++) PrepareSlices();
sources_[it]->Init(&init_data); for (size_t ii = 0; ii < sources_.size(); ii++) {
sources_[ii]->SetScheduler(sched_);
for (int ii = 0; ii < Slices; ii++) sink_counter_[ii] = 0; }
for (size_t ii = 0; ii < processes_.size(); ii++) {
processes_[ii]->SetScheduler(sched_);
}
for (size_t ii = 0; ii < sinks_.size(); ii++) {
sinks_[ii]->SetScheduler(sched_);
}
}
int clock = 0; int clock = 0;
while (clock >= 0) { while (clock >= 0) {
const int idx = clock % Slices; const int idx = clock % slices_;
while (sink_counter_[idx] > 0) embb::base::Thread::CurrentYield(); while (sink_counter_[idx] > 0) embb::base::Thread::CurrentYield();
sched->WaitForSlice(idx); sched_->WaitForSlice(idx);
if (!SpawnClock(clock)) if (!SpawnClock(clock))
break; break;
clock++; clock++;
} }
int ii = clock - Slices + 1; int ii = clock - slices_ + 1;
if (ii < 0) ii = 0; if (ii < 0) ii = 0;
for (; ii < clock; ii++) { for (; ii < clock; ii++) {
const int idx = ii % Slices; const int idx = ii % slices_;
while (sink_counter_[idx] > 0) embb::base::Thread::CurrentYield(); while (sink_counter_[idx] > 0) embb::base::Thread::CurrentYield();
sched->WaitForSlice(idx); sched_->WaitForSlice(idx);
} }
} }
...@@ -841,35 +915,26 @@ class Network : public internal::ClockListener { ...@@ -841,35 +915,26 @@ class Network : public internal::ClockListener {
* corresponding slot, thus allowing a new token to be emitted. * corresponding slot, thus allowing a new token to be emitted.
*/ */
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
const int idx = clock % Slices; const int idx = clock % slices_;
const int cnt = --sink_counter_[idx]; assert(sink_counter_[idx] > 0);
if (cnt < 0) --sink_counter_[idx];
EMBB_THROW(embb::base::ErrorException,
"More sinks than expected signaled reception of given clock.")
}
/**
* Internal.
* \internal
* Gets called when an init token has reached all sinks.
*/
virtual void OnInit(internal::InitData * /*sched*/) {
sink_count_++;
} }
private: private:
std::vector<internal::Node*> processes_; std::vector<internal::Node*> processes_;
std::vector<internal::Node*> sources_; std::vector<internal::Node*> sources_;
std::vector<internal::Node*> sinks_; std::vector<internal::Node*> sinks_;
embb::base::Atomic<int> sink_counter_[Slices]; embb::base::Atomic<int> * sink_counter_;
int sink_count_; int sink_count_;
int slices_;
internal::Scheduler * sched_;
#if EMBB_DATAFLOW_TRACE_SIGNAL_HISTORY #if EMBB_DATAFLOW_TRACE_SIGNAL_HISTORY
std::vector<int> spawn_history_[Slices]; std::vector<int> spawn_history_[Slices];
#endif #endif
bool SpawnClock(int clock) { bool SpawnClock(int clock) {
const int idx = clock % Slices; const int idx = clock % slices_;
bool result = true; bool result = true;
#if EMBB_DATAFLOW_TRACE_SIGNAL_HISTORY #if EMBB_DATAFLOW_TRACE_SIGNAL_HISTORY
spawn_history_[idx].push_back(clock); spawn_history_[idx].push_back(clock);
...@@ -880,6 +945,19 @@ class Network : public internal::ClockListener { ...@@ -880,6 +945,19 @@ class Network : public internal::ClockListener {
} }
return result; return result;
} }
void PrepareSlices() {
sched_ = embb::base::Allocation::New<internal::SchedulerMTAPI>(slices_);
if (sched_->GetSlices() != slices_) {
slices_ = sched_->GetSlices();
}
sink_counter_ = reinterpret_cast<embb::base::Atomic<int>*>(
embb::base::Allocation::Allocate(
sizeof(embb::base::Atomic<int>)*slices_));
for (int ii = 0; ii < slices_; ii++) {
sink_counter_[ii] = 0;
}
}
}; };
#endif // DOXYGEN #endif // DOXYGEN
......
...@@ -39,15 +39,15 @@ ...@@ -39,15 +39,15 @@
#define NUM_SLICES 8 #define NUM_SLICES 8
#define TEST_COUNT 12 #define TEST_COUNT 12
typedef embb::dataflow::Network<NUM_SLICES> MyNetwork; typedef embb::dataflow::Network MyNetwork;
typedef MyNetwork::ConstantSource< int > MyConstantSource; typedef MyNetwork::ConstantSource< int > MyConstantSource;
typedef MyNetwork::Source< int > MySource; typedef MyNetwork::Source< int > MySource;
typedef MyNetwork::SerialProcess< MyNetwork::Inputs<int>::Type, typedef MyNetwork::SerialProcess< MyNetwork::Inputs<int>,
MyNetwork::Outputs<bool>::Type > MyPred; MyNetwork::Outputs<bool> > MyPred;
typedef MyNetwork::ParallelProcess< MyNetwork::Inputs<int>::Type, typedef MyNetwork::ParallelProcess< MyNetwork::Inputs<int>,
MyNetwork::Outputs<int>::Type > MyFilter; MyNetwork::Outputs<int> > MyFilter;
typedef MyNetwork::ParallelProcess< MyNetwork::Inputs<int, int>::Type, typedef MyNetwork::ParallelProcess< MyNetwork::Inputs<int, int>,
MyNetwork::Outputs<int>::Type > MyMult; MyNetwork::Outputs<int> > MyMult;
typedef MyNetwork::Sink< int > MySink; typedef MyNetwork::Sink< int > MySink;
typedef MyNetwork::Switch< int > MySwitch; typedef MyNetwork::Switch< int > MySwitch;
typedef MyNetwork::Select< int > MySelect; typedef MyNetwork::Select< int > MySelect;
...@@ -165,15 +165,16 @@ void SimpleTest::TestBasic() { ...@@ -165,15 +165,16 @@ void SimpleTest::TestBasic() {
for (int ii = 0; ii < 10000; ii++) { for (int ii = 0; ii < 10000; ii++) {
ArraySink<TEST_COUNT> asink; ArraySink<TEST_COUNT> asink;
MyNetwork network; MyNetwork network(NUM_SLICES);
MyConstantSource constant(4); MyConstantSource constant(network, 4);
MySource source(embb::base::MakeFunction(sourceFunc)); MySource source(network, embb::base::MakeFunction(sourceFunc));
MyFilter filter(embb::base::MakeFunction(filterFunc)); MyFilter filter(network, embb::base::MakeFunction(filterFunc));
MyMult mult(embb::base::MakeFunction(multFunc)); MyMult mult(network, embb::base::MakeFunction(multFunc));
MySink sink(embb::base::MakeFunction(asink, &ArraySink<TEST_COUNT>::Run)); MySink sink(network,
MyPred pred(embb::base::MakeFunction(predFunc)); embb::base::MakeFunction(asink, &ArraySink<TEST_COUNT>::Run));
MySwitch sw; MyPred pred(network, embb::base::MakeFunction(predFunc));
MySelect sel; MySwitch sw(network);
MySelect sel(network);
for (int kk = 0; kk < TEST_COUNT; kk++) { for (int kk = 0; kk < TEST_COUNT; kk++) {
source_array[kk] = -1; source_array[kk] = -1;
...@@ -208,10 +209,10 @@ void SimpleTest::TestBasic() { ...@@ -208,10 +209,10 @@ void SimpleTest::TestBasic() {
sel.GetOutput<0>() >> sink.GetInput<0>(); sel.GetOutput<0>() >> sink.GetInput<0>();
network.AddSource(constant);
network.AddSource(source);
try { try {
if (!network.IsValid()) {
EMBB_THROW(embb::base::ErrorException, "network is invalid");
}
network(); network();
} catch (embb::base::ErrorException & e) { } catch (embb::base::ErrorException & e) {
PT_ASSERT_MSG(false, e.What()); PT_ASSERT_MSG(false, e.What());
......
...@@ -6,15 +6,14 @@ ...@@ -6,15 +6,14 @@
Network::Source<int> Network::Source<int>
source1( source1(
network,
embb::base::MakeFunction(producer1, &Producer<int>::Run) ), embb::base::MakeFunction(producer1, &Producer<int>::Run) ),
source2( source2(
network,
embb::base::MakeFunction(producer2, &Producer<int>::Run) ), embb::base::MakeFunction(producer2, &Producer<int>::Run) ),
source3( source3(
network,
embb::base::MakeFunction(producer3, &Producer<int>::Run) ), embb::base::MakeFunction(producer3, &Producer<int>::Run) ),
source4( source4(
network,
embb::base::MakeFunction(producer4, &Producer<int>::Run) ); embb::base::MakeFunction(producer4, &Producer<int>::Run) );
nw.AddSource(source1);
nw.AddSource(source2);
nw.AddSource(source3);
nw.AddSource(source4);
Network::ParallelProcess< Network::ParallelProcess<
Network::Inputs<std::string>::Type, Network::Inputs<std::string>,
Network::Outputs<std::string>::Type> replace( Network::Outputs<std::string> > replace(
embb::base::MakeFunction(ReplaceFunction) network, embb::base::MakeFunction(ReplaceFunction)
); );
Network::Sink<std::string> write( Network::Sink<std::string> write(
embb::base::MakeFunction(SinkFunction) network, embb::base::MakeFunction(SinkFunction)
); );
Network::Source<std::string> read( Network::Source<std::string> read(
embb::base::MakeFunction(SourceFunction) network, embb::base::MakeFunction(SourceFunction)
); );
...@@ -52,10 +52,10 @@ std::string with("hello"); ...@@ -52,10 +52,10 @@ std::string with("hello");
#include "dataflow/dataflow_sink_function-snippet.h" #include "dataflow/dataflow_sink_function-snippet.h"
void RunDataflowLinear() { void RunDataflowLinear() {
#include "dataflow/dataflow_make-snippet.h"
#include "dataflow/dataflow_declare_source-snippet.h" #include "dataflow/dataflow_declare_source-snippet.h"
#include "dataflow/dataflow_declare_replace-snippet.h" #include "dataflow/dataflow_declare_replace-snippet.h"
#include "dataflow/dataflow_declare_sink-snippet.h" #include "dataflow/dataflow_declare_sink-snippet.h"
#include "dataflow/dataflow_connect-snippet.h" #include "dataflow/dataflow_connect-snippet.h"
#include "dataflow/dataflow_add-snippet.h"
#include "dataflow/dataflow_run-snippet.h" #include "dataflow/dataflow_run-snippet.h"
} }
typedef embb::dataflow::Network<2> Network; typedef embb::dataflow::Network Network;
static Network nw;
...@@ -48,22 +48,28 @@ static int SimpleRand(int & seed) { ...@@ -48,22 +48,28 @@ static int SimpleRand(int & seed) {
#include "dataflow/dataflow_network-snippet.h" #include "dataflow/dataflow_network-snippet.h"
void RunDataflowNonLinear() { void RunDataflowNonLinear() {
#include "dataflow/dataflow_make-snippet.h"
#include "dataflow/dataflow_declare_add_sources-snippet.h" #include "dataflow/dataflow_declare_add_sources-snippet.h"
Comparator<int> comparator; Comparator<int> comparator;
Network::ParallelProcess< Network::ParallelProcess<
Network::Inputs<int, int>::Type, Network::Outputs<int, int>::Type> Network::Inputs<int, int>, Network::Outputs<int, int> >
process1( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ), process1(network,
process2( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ), embb::base::MakeFunction(comparator, &Comparator<int>::Run)),
process3( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ), process2(network,
process4( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ), embb::base::MakeFunction(comparator, &Comparator<int>::Run)),
process5( embb::base::MakeFunction(comparator, &Comparator<int>::Run) ); process3(network,
embb::base::MakeFunction(comparator, &Comparator<int>::Run)),
process4(network,
embb::base::MakeFunction(comparator, &Comparator<int>::Run)),
process5(network,
embb::base::MakeFunction(comparator, &Comparator<int>::Run));
Consumer<int> consumer; Consumer<int> consumer;
Network::Sink<int, int, int, int> Network::Sink<int, int, int, int>
sink1(embb::base::MakeFunction(consumer, &Consumer<int>::Run)); sink1(network, embb::base::MakeFunction(consumer, &Consumer<int>::Run));
source1.GetOutput<0>() >> process1.GetInput<0>(); source1.GetOutput<0>() >> process1.GetInput<0>();
source2.GetOutput<0>() >> process2.GetInput<0>(); source2.GetOutput<0>() >> process2.GetInput<0>();
...@@ -83,5 +89,5 @@ void RunDataflowNonLinear() { ...@@ -83,5 +89,5 @@ void RunDataflowNonLinear() {
process5.GetOutput<1>() >> sink1.GetInput<2>(); process5.GetOutput<1>() >> sink1.GetInput<2>();
process4.GetOutput<1>() >> sink1.GetInput<3>(); process4.GetOutput<1>() >> sink1.GetInput<3>();
nw(); #include "dataflow/dataflow_run-snippet.h"
} }
...@@ -104,10 +104,14 @@ This pipeline can be easily implemented using the Dataflow building block. As th ...@@ -104,10 +104,14 @@ This pipeline can be easily implemented using the Dataflow building block. As th
% %
Then, we have to construct a \emph{network}. A network consists of a set of processes that are connected by communication channels. Then, we have to construct a \emph{network}. A network consists of a set of processes that are connected by communication channels.
%\footnote{Pipelines belong to the most simple networks, where the processes are connected in string-like (linear) fashion.} %\footnote{Pipelines belong to the most simple networks, where the processes are connected in string-like (linear) fashion.}
\embb provides a class template \lstinline|Network| that can be customized to your needs. For the moment, we are using 2 as a template argument: \embb provides a class \lstinline|Network| that handles data routing and scheduling of your processes:
% %
\\\inputlisting{../examples/dataflow/dataflow_network-snippet.h} \\\inputlisting{../examples/dataflow/dataflow_network-snippet.h}
% %
We need to prepare the network for the desired maximum number of elements that can be in the network at a time. The number of elements is limited to avoid that the network is flooded with new elements before the previous elements have been processed. In a linear pipeline, for example, this may happen if the source is faster than the sink. In our example, at most four elements may be processed simultaneously: one in the source, one in the sink, and two in the middle stage (see below). Finding an optimal value depends on the application and usually requires some experimentation. In general, large values boost the throughput but also increase the latency. Conversely, small values reduce the latency but may lead to a drop of performance in terms of throughput:
%
\\\inputlisting{../examples/dataflow/dataflow_make-snippet.h}
%
As the next step, we have to construct the processes shown in Figure~\ref{fig:replace_par}. The easiest way to construct a process is to wrap the user-defined code in a lambda function and to pass it to the network. The network constructs an object for that process and executes the lambda function whenever new data is available. There are several methods for constructing processes depending on their type. The process \textbf{read} is a \emph{source} process, since it produces data (by reading it from the specified file) but does not consume any data. Source processes are constructed from a function object As the next step, we have to construct the processes shown in Figure~\ref{fig:replace_par}. The easiest way to construct a process is to wrap the user-defined code in a lambda function and to pass it to the network. The network constructs an object for that process and executes the lambda function whenever new data is available. There are several methods for constructing processes depending on their type. The process \textbf{read} is a \emph{source} process, since it produces data (by reading it from the specified file) but does not consume any data. Source processes are constructed from a function object
% %
\\\inputlisting{../examples/dataflow/dataflow_source_function-snippet.h} \\\inputlisting{../examples/dataflow/dataflow_source_function-snippet.h}
...@@ -142,20 +146,14 @@ is used to construct the sink: ...@@ -142,20 +146,14 @@ is used to construct the sink:
\emph{\textbf{Note:} If you parallelize your own application using \embb and your compiler emits a lengthy error message containing lots of templates, it is very likely that for at least one process, the ports and their directions do not match the signature of the given function.} \emph{\textbf{Note:} If you parallelize your own application using \embb and your compiler emits a lengthy error message containing lots of templates, it is very likely that for at least one process, the ports and their directions do not match the signature of the given function.}
The network needs to know about the source declared above, so we add it to our network:
%
\\\inputlisting{../examples/dataflow/dataflow_add-snippet.h}
%
As the last step, we have to connect the processes (ports). This is straightforward using the C++ stream operator: As the last step, we have to connect the processes (ports). This is straightforward using the C++ stream operator:
% %
\\\inputlisting{../examples/dataflow/dataflow_connect-snippet.h} \\\inputlisting{../examples/dataflow/dataflow_connect-snippet.h}
% %
Once all connections have been established, we can start the network: Then we can start the network:
% %
\\\inputlisting{../examples/dataflow/dataflow_run-snippet.h} \\\inputlisting{../examples/dataflow/dataflow_run-snippet.h}
% %
The integer given as a template parameter to the network specifies the maximum number of elements that can be in the network at a time. The number of elements is limited to avoid that the network is flooded with new elements before the previous elements have been processed. In a linear pipeline, for example, this may happen if the source is faster than the sink. In our example, at most four elements may be processed simultaneously: one in the source, one in the sink, and two in the middle stage (see above). Finding an optimal value depends on the application and usually requires some experimentation. In general, large values boost the throughput but also increase the latency. Conversely, small values reduce the latency but may lead to a drop of performance in terms of throughput.
Note that you will probably not observe a speedup when you run this program on a multicore processor. One reason for this is that input$/$output operations like reading a file from the hard disk and writing the output to the screen are typically a bottleneck. Moreover, the amount of work done in the middle stage of the pipeline (\textbf{replace}) is rather low. To outweigh the overhead for parallel execution, the amount of work must be much higher. In image processing, for example, a single pipeline stage may process a complete image. To sum up, we haven chosen this example for its simplicity, not for its efficiency. Note that you will probably not observe a speedup when you run this program on a multicore processor. One reason for this is that input$/$output operations like reading a file from the hard disk and writing the output to the screen are typically a bottleneck. Moreover, the amount of work done in the middle stage of the pipeline (\textbf{replace}) is rather low. To outweigh the overhead for parallel execution, the amount of work must be much higher. In image processing, for example, a single pipeline stage may process a complete image. To sum up, we haven chosen this example for its simplicity, not for its efficiency.
......
...@@ -250,6 +250,17 @@ extern "C" { ...@@ -250,6 +250,17 @@ extern "C" {
#endif #endif
/* ---- MCA ORGANIZATION IDS ----------------------------------------------- */
#define MCA_ORG_ID_PSI 0 /* PolyCore Software, Inc. */
#define MCA_ORG_ID_FSL 1 /* Freescale, Inc. */
#define MCA_ORG_ID_MGC 2 /* Mentor Graphics, Corp. */
#define MCA_ORG_ID_ADI 3 /* Analog Devices */
#define MCA_ORG_ID_SIE 4 /* Siemens */
#define MCA_ORG_ID_EMB 5 /* EMB2 project */
#define MCA_ORG_ID_TBD 6 /* TBD */
/* ---- BASIC DEFINITIONS -------------------------------------------------- */ /* ---- BASIC DEFINITIONS -------------------------------------------------- */
/** marks input parameters */ /** marks input parameters */
...@@ -307,8 +318,22 @@ typedef mtapi_uint_t mtapi_size_t; ...@@ -307,8 +318,22 @@ typedef mtapi_uint_t mtapi_size_t;
* \ingroup RUNTIME_INIT_SHUTDOWN * \ingroup RUNTIME_INIT_SHUTDOWN
*/ */
struct mtapi_info_struct { struct mtapi_info_struct {
unsigned int hardware_concurrency; /**< number of CPU cores */ mtapi_uint_t mtapi_version; /**< The three last (rightmost) hex
unsigned int used_memory; /**< bytes of memory used by MTAPI */ digits are the minor number, and
those left of the minor number are
the major number. */
mtapi_uint_t organization_id; /**< Implementation vendor or
organization ID. */
mtapi_uint_t implementation_version; /**< The three last (rightmost) hex
digits are the minor number, and
those left of the minor number are
the major number.*/
mtapi_uint_t number_of_domains; /**< Number of domains allowed by the
implementation.*/
mtapi_uint_t number_of_nodes; /**< Number of nodes allowed by the
implementation.*/
mtapi_uint_t hardware_concurrency; /**< Number of CPU cores available. */
mtapi_uint_t used_memory; /**< Bytes of memory used by MTAPI. */
}; };
/** /**
......
...@@ -279,6 +279,7 @@ void mtapi_group_wait_any( ...@@ -279,6 +279,7 @@ void mtapi_group_wait_any(
MTAPI_IN mtapi_timeout_t timeout, MTAPI_IN mtapi_timeout_t timeout,
MTAPI_OUT mtapi_status_t* status) { MTAPI_OUT mtapi_status_t* status) {
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
void* local_result = MTAPI_NULL;
embb_mtapi_log_trace("mtapi_group_wait_any() called\n"); embb_mtapi_log_trace("mtapi_group_wait_any() called\n");
...@@ -335,10 +336,7 @@ void mtapi_group_wait_any( ...@@ -335,10 +336,7 @@ void mtapi_group_wait_any(
} }
/* was there a timeout, or is there a result? */ /* was there a timeout, or is there a result? */
if (MTAPI_NULL != local_task) { if (MTAPI_NULL != local_task) {
/* store result */ local_result = local_task->result_buffer;
if (MTAPI_NULL != result) {
*result = local_task->result_buffer;
}
/* return error code set by the task */ /* return error code set by the task */
local_status = local_task->error_code; local_status = local_task->error_code;
...@@ -356,6 +354,11 @@ void mtapi_group_wait_any( ...@@ -356,6 +354,11 @@ void mtapi_group_wait_any(
local_status = MTAPI_ERR_NODE_NOTINIT; local_status = MTAPI_ERR_NODE_NOTINIT;
} }
/* store result */
if (MTAPI_NULL != result) {
*result = local_result;
}
mtapi_status_set(status, local_status); mtapi_status_set(status, local_status);
embb_mtapi_log_trace("mtapi_group_wait_any() returns\n"); embb_mtapi_log_trace("mtapi_group_wait_any() returns\n");
} }
......
...@@ -36,14 +36,19 @@ void embb_mtapi_id_pool_initialize( ...@@ -36,14 +36,19 @@ void embb_mtapi_id_pool_initialize(
mtapi_uint_t capacity) { mtapi_uint_t capacity) {
mtapi_uint_t ii; mtapi_uint_t ii;
that->capacity = capacity;
that->id_buffer = (mtapi_uint_t*) that->id_buffer = (mtapi_uint_t*)
embb_mtapi_alloc_allocate(sizeof(mtapi_uint_t)*(capacity + 1)); embb_mtapi_alloc_allocate(sizeof(mtapi_uint_t)*(capacity + 1));
that->id_buffer[0] = EMBB_MTAPI_IDPOOL_INVALID_ID; if (NULL != that->id_buffer) {
for (ii = 1; ii <= capacity; ii++) { that->capacity = capacity;
that->id_buffer[ii] = ii; that->id_buffer[0] = EMBB_MTAPI_IDPOOL_INVALID_ID;
for (ii = 1; ii <= capacity; ii++) {
that->id_buffer[ii] = ii;
}
that->ids_available = capacity;
} else {
that->capacity = 0;
that->ids_available = 0;
} }
that->ids_available = capacity;
that->put_id_position = 0; that->put_id_position = 0;
that->get_id_position = 1; that->get_id_position = 1;
embb_spin_init(&that->lock); embb_spin_init(&that->lock);
......
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
mtapi_boolean_t embb_mtapi_job_initialize_list(embb_mtapi_node_t * node) { mtapi_boolean_t embb_mtapi_job_initialize_list(embb_mtapi_node_t * node) {
node->job_list = (embb_mtapi_job_t*)embb_mtapi_alloc_allocate( node->job_list = (embb_mtapi_job_t*)embb_mtapi_alloc_allocate(
sizeof(embb_mtapi_job_t)*(node->attributes.max_jobs + 1)); sizeof(embb_mtapi_job_t)*(node->attributes.max_jobs + 1));
if (NULL == node->job_list) {
return MTAPI_FALSE;
}
mtapi_uint_t ii; mtapi_uint_t ii;
for (ii = 0; ii <= node->attributes.max_jobs; ii++) { for (ii = 0; ii <= node->attributes.max_jobs; ii++) {
embb_mtapi_job_initialize( embb_mtapi_job_initialize(
...@@ -112,11 +115,15 @@ void embb_mtapi_job_initialize( ...@@ -112,11 +115,15 @@ void embb_mtapi_job_initialize(
that->domain_id = 0; that->domain_id = 0;
that->node_id = 0; that->node_id = 0;
that->num_actions = 0; that->num_actions = 0;
that->max_actions = max_actions;
that->actions = (mtapi_action_hndl_t*) that->actions = (mtapi_action_hndl_t*)
embb_mtapi_alloc_allocate(sizeof(mtapi_action_hndl_t)*max_actions); embb_mtapi_alloc_allocate(sizeof(mtapi_action_hndl_t)*max_actions);
for (ii = 0; ii < max_actions; ii++) { if (NULL != that->actions) {
that->actions[ii].id = EMBB_MTAPI_IDPOOL_INVALID_ID; that->max_actions = max_actions;
for (ii = 0; ii < max_actions; ii++) {
that->actions[ii].id = EMBB_MTAPI_IDPOOL_INVALID_ID;
}
} else {
that->max_actions = 0;
} }
} }
...@@ -159,7 +166,7 @@ void embb_mtapi_job_remove_action( ...@@ -159,7 +166,7 @@ void embb_mtapi_job_remove_action(
embb_mtapi_action_t * action) { embb_mtapi_action_t * action) {
assert(MTAPI_NULL != that); assert(MTAPI_NULL != that);
assert(MTAPI_NULL != action); assert(MTAPI_NULL != action);
mtapi_uint_t ii = 0; mtapi_uint_t ii;
for (ii = 0; ii + 1 < that->num_actions; ii++) { for (ii = 0; ii + 1 < that->num_actions; ii++) {
if (that->actions[ii].id == action->handle.id && if (that->actions[ii].id == action->handle.id &&
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#include <embb_mtapi_scheduler_t.h> #include <embb_mtapi_scheduler_t.h>
#include <embb_mtapi_attr.h> #include <embb_mtapi_attr.h>
#include <embb/base/c/internal/cmake_config.h>
static embb_mtapi_node_t* embb_mtapi_node_instance = NULL; static embb_mtapi_node_t* embb_mtapi_node_instance = NULL;
...@@ -115,29 +117,39 @@ void mtapi_initialize( ...@@ -115,29 +117,39 @@ void mtapi_initialize(
node->attributes.max_tasks); node->attributes.max_tasks);
node->queue_pool = embb_mtapi_queue_pool_new( node->queue_pool = embb_mtapi_queue_pool_new(
node->attributes.max_queues); node->attributes.max_queues);
if (MTAPI_NULL == node->job_list ||
MTAPI_NULL == node->action_pool ||
MTAPI_NULL == node->group_pool ||
MTAPI_NULL == node->task_pool ||
MTAPI_NULL == node->queue_pool) {
mtapi_finalize(NULL);
local_status = MTAPI_ERR_NODE_INITFAILED;
}
/* initialize scheduler for local node */ if (local_status == MTAPI_SUCCESS) {
node->scheduler = embb_mtapi_scheduler_new(); /* initialize scheduler for local node */
if (MTAPI_NULL != node->scheduler) { node->scheduler = embb_mtapi_scheduler_new();
/* fill information structure */ if (MTAPI_NULL != node->scheduler) {
node->info.hardware_concurrency = embb_core_count_available(); /* fill information structure */
node->info.used_memory = embb_mtapi_alloc_get_bytes_allocated(); node->info.mtapi_version = 0x1000; // mtapi version 1.0
if (MTAPI_NULL != mtapi_info) { node->info.organization_id = MCA_ORG_ID_EMB;
*mtapi_info = node->info; node->info.implementation_version =
} EMBB_BASE_VERSION_MAJOR * 0x1000 + EMBB_BASE_VERSION_MINOR;
node->info.number_of_domains = ~0u;
/* initialization succeeded, tell workers to start working */ node->info.number_of_nodes = ~0u;
embb_atomic_store_int(&node->is_scheduler_running, MTAPI_TRUE); node->info.hardware_concurrency = embb_core_count_available();
node->info.used_memory = embb_mtapi_alloc_get_bytes_allocated();
if (MTAPI_SUCCESS != local_status) { if (MTAPI_NULL != mtapi_info) {
*mtapi_info = node->info;
}
/* initialization succeeded, tell workers to start working */
embb_atomic_store_int(&node->is_scheduler_running, MTAPI_TRUE);
} else {
mtapi_finalize(MTAPI_NULL); mtapi_finalize(MTAPI_NULL);
local_status = MTAPI_ERR_NODE_INITFAILED; local_status = MTAPI_ERR_NODE_INITFAILED;
} }
} else {
mtapi_finalize(MTAPI_NULL);
local_status = MTAPI_ERR_NODE_INITFAILED;
} }
} else { } else {
embb_mtapi_alloc_deallocate(node); embb_mtapi_alloc_deallocate(node);
local_status = MTAPI_ERR_PARAMETER; local_status = MTAPI_ERR_PARAMETER;
...@@ -163,19 +175,29 @@ void mtapi_finalize(MTAPI_OUT mtapi_status_t* status) { ...@@ -163,19 +175,29 @@ void mtapi_finalize(MTAPI_OUT mtapi_status_t* status) {
} }
/* finalize storage in reverse order */ /* finalize storage in reverse order */
embb_mtapi_queue_pool_delete(node->queue_pool); if (MTAPI_NULL != node->queue_pool) {
node->queue_pool = MTAPI_NULL; embb_mtapi_queue_pool_delete(node->queue_pool);
node->queue_pool = MTAPI_NULL;
}
embb_mtapi_task_pool_delete(node->task_pool); if (MTAPI_NULL != node->task_pool) {
node->task_pool = MTAPI_NULL; embb_mtapi_task_pool_delete(node->task_pool);
node->task_pool = MTAPI_NULL;
}
embb_mtapi_group_pool_delete(node->group_pool); if (MTAPI_NULL != node->group_pool) {
node->group_pool = MTAPI_NULL; embb_mtapi_group_pool_delete(node->group_pool);
node->group_pool = MTAPI_NULL;
}
embb_mtapi_action_pool_delete(node->action_pool); if (MTAPI_NULL != node->action_pool) {
node->action_pool = MTAPI_NULL; embb_mtapi_action_pool_delete(node->action_pool);
node->action_pool = MTAPI_NULL;
}
embb_mtapi_job_finalize_list(node); if (MTAPI_NULL != node->job_list) {
embb_mtapi_job_finalize_list(node);
}
/* free system instance */ /* free system instance */
embb_mtapi_alloc_deallocate(node); embb_mtapi_alloc_deallocate(node);
......
...@@ -61,13 +61,18 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_initialize( \ ...@@ -61,13 +61,18 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_initialize( \
embb_mtapi_id_pool_initialize(&that->id_pool, capacity); \ embb_mtapi_id_pool_initialize(&that->id_pool, capacity); \
that->storage = (embb_mtapi_##TYPE##_t*)embb_mtapi_alloc_allocate( \ that->storage = (embb_mtapi_##TYPE##_t*)embb_mtapi_alloc_allocate( \
sizeof(embb_mtapi_##TYPE##_t)*(capacity + 1)); \ sizeof(embb_mtapi_##TYPE##_t)*(capacity + 1)); \
for (ii = 0; ii <= capacity; ii++) { \ if (NULL != that->storage) { \
that->storage[ii].handle.id = EMBB_MTAPI_IDPOOL_INVALID_ID; \ for (ii = 0; ii <= capacity; ii++) { \
that->storage[ii].handle.tag = 0; \ that->storage[ii].handle.id = EMBB_MTAPI_IDPOOL_INVALID_ID; \
that->storage[ii].handle.tag = 0; \
} \
/* use entry 0 as invalid */ \
embb_mtapi_##TYPE##_initialize(that->storage); \
return MTAPI_TRUE; \
} else { \
that->id_pool.ids_available = 0; \
return MTAPI_FALSE; \
} \ } \
/* use entry 0 as invalid */ \
embb_mtapi_##TYPE##_initialize(that->storage); \
return MTAPI_TRUE; \
} \ } \
\ \
void embb_mtapi_##TYPE##_pool_finalize(embb_mtapi_##TYPE##_pool_t * that) { \ void embb_mtapi_##TYPE##_pool_finalize(embb_mtapi_##TYPE##_pool_t * that) { \
......
...@@ -325,7 +325,7 @@ mtapi_queue_hndl_t mtapi_queue_get( ...@@ -325,7 +325,7 @@ mtapi_queue_hndl_t mtapi_queue_get(
if (embb_mtapi_node_is_initialized()) { if (embb_mtapi_node_is_initialized()) {
embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
mtapi_uint_t ii = 0; mtapi_uint_t ii;
local_status = MTAPI_ERR_QUEUE_INVALID; local_status = MTAPI_ERR_QUEUE_INVALID;
for (ii = 0; ii < node->attributes.max_queues; ii++) { for (ii = 0; ii < node->attributes.max_queues; ii++) {
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <embb_mtapi_action_t.h> #include <embb_mtapi_action_t.h>
#include <embb_mtapi_alloc.h> #include <embb_mtapi_alloc.h>
#include <embb_mtapi_queue_t.h> #include <embb_mtapi_queue_t.h>
#include <embb_mtapi_group_t.h>
/* ---- CLASS MEMBERS ------------------------------------------------------ */ /* ---- CLASS MEMBERS ------------------------------------------------------ */
...@@ -78,8 +79,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task_vhpf( ...@@ -78,8 +79,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task_vhpf(
embb_mtapi_node_t * node, embb_mtapi_node_t * node,
embb_mtapi_thread_context_t * thread_context) { embb_mtapi_thread_context_t * thread_context) {
embb_mtapi_task_t * task = MTAPI_NULL; embb_mtapi_task_t * task = MTAPI_NULL;
mtapi_uint_t ii = 0; mtapi_uint_t ii;
mtapi_uint_t kk = 0;
assert(MTAPI_NULL != that); assert(MTAPI_NULL != that);
assert(MTAPI_NULL != node); assert(MTAPI_NULL != node);
...@@ -102,6 +102,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task_vhpf( ...@@ -102,6 +102,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task_vhpf(
*/ */
mtapi_uint_t context_index = mtapi_uint_t context_index =
(thread_context->worker_index + 1) % that->worker_count; (thread_context->worker_index + 1) % that->worker_count;
mtapi_uint_t kk;
for (kk = 0; for (kk = 0;
kk < that->worker_count - 1 && MTAPI_NULL == task; kk < that->worker_count - 1 && MTAPI_NULL == task;
kk++) { kk++) {
...@@ -121,8 +122,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task_lf( ...@@ -121,8 +122,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task_lf(
embb_mtapi_node_t * node, embb_mtapi_node_t * node,
embb_mtapi_thread_context_t * thread_context) { embb_mtapi_thread_context_t * thread_context) {
embb_mtapi_task_t * task = MTAPI_NULL; embb_mtapi_task_t * task = MTAPI_NULL;
mtapi_uint_t prio = 0; mtapi_uint_t prio;
mtapi_uint_t kk = 0;
assert(MTAPI_NULL != that); assert(MTAPI_NULL != that);
assert(MTAPI_NULL != node); assert(MTAPI_NULL != node);
...@@ -153,6 +153,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task_lf( ...@@ -153,6 +153,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task_lf(
prio++) { prio++) {
mtapi_uint_t context_index = mtapi_uint_t context_index =
(thread_context->worker_index + 1) % that->worker_count; (thread_context->worker_index + 1) % that->worker_count;
mtapi_uint_t kk;
for (kk = 0; for (kk = 0;
kk < that->worker_count - 1 && MTAPI_NULL == task; kk < that->worker_count - 1 && MTAPI_NULL == task;
kk++) { kk++) {
...@@ -195,7 +196,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task( ...@@ -195,7 +196,7 @@ embb_mtapi_task_t * embb_mtapi_scheduler_get_next_task(
embb_mtapi_thread_context_t * embb_mtapi_scheduler_get_current_thread_context( embb_mtapi_thread_context_t * embb_mtapi_scheduler_get_current_thread_context(
embb_mtapi_scheduler_t * that) { embb_mtapi_scheduler_t * that) {
mtapi_uint_t ii = 0; mtapi_uint_t ii;
embb_mtapi_thread_context_t * context = NULL; embb_mtapi_thread_context_t * context = NULL;
assert(MTAPI_NULL != that); assert(MTAPI_NULL != that);
...@@ -293,6 +294,8 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -293,6 +294,8 @@ int embb_mtapi_scheduler_worker(void * arg) {
/* check if there was work */ /* check if there was work */
if (MTAPI_NULL != task) { if (MTAPI_NULL != task) {
embb_mtapi_queue_t * local_queue = MTAPI_NULL; embb_mtapi_queue_t * local_queue = MTAPI_NULL;
embb_mtapi_group_t * local_group = MTAPI_NULL;
embb_mtapi_action_t * local_action = MTAPI_NULL;
/* is task associated with a queue? */ /* is task associated with a queue? */
if (embb_mtapi_queue_pool_is_handle_valid( if (embb_mtapi_queue_pool_is_handle_valid(
...@@ -302,6 +305,21 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -302,6 +305,21 @@ int embb_mtapi_scheduler_worker(void * arg) {
node->queue_pool, task->queue); node->queue_pool, task->queue);
} }
/* is task associated with a group? */
if (embb_mtapi_group_pool_is_handle_valid(
node->group_pool, task->group)) {
local_group =
embb_mtapi_group_pool_get_storage_for_handle(
node->group_pool, task->group);
}
if (embb_mtapi_action_pool_is_handle_valid(
node->action_pool, task->action)) {
local_action =
embb_mtapi_action_pool_get_storage_for_handle(
node->action_pool, task->action);
}
switch (embb_atomic_load_int(&task->state)) { switch (embb_atomic_load_int(&task->state)) {
case MTAPI_TASK_SCHEDULED: case MTAPI_TASK_SCHEDULED:
/* multi-instance task, another instance might be running */ /* multi-instance task, another instance might be running */
...@@ -328,7 +346,7 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -328,7 +346,7 @@ int embb_mtapi_scheduler_worker(void * arg) {
break; break;
case MTAPI_TASK_CANCELLED: case MTAPI_TASK_CANCELLED:
/* set return value to canceled */ /* set return value to cancelled */
task->error_code = MTAPI_ERR_ACTION_CANCELLED; task->error_code = MTAPI_ERR_ACTION_CANCELLED;
if (embb_atomic_fetch_and_add_unsigned_int( if (embb_atomic_fetch_and_add_unsigned_int(
&task->instances_todo, (unsigned int)-1) == 0) { &task->instances_todo, (unsigned int)-1) == 0) {
...@@ -336,6 +354,12 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -336,6 +354,12 @@ int embb_mtapi_scheduler_worker(void * arg) {
if (MTAPI_NULL != local_queue) { if (MTAPI_NULL != local_queue) {
embb_mtapi_queue_task_finished(local_queue); embb_mtapi_queue_task_finished(local_queue);
} }
if (MTAPI_NULL != local_group) {
embb_mtapi_task_queue_push(&local_group->queue, task);
}
}
if (MTAPI_NULL != local_action) {
embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1);
} }
break; break;
...@@ -434,7 +458,7 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode( ...@@ -434,7 +458,7 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode(
embb_mtapi_scheduler_t * that, embb_mtapi_scheduler_t * that,
embb_mtapi_scheduler_mode_t mode) { embb_mtapi_scheduler_mode_t mode) {
embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
mtapi_uint_t ii = 0; mtapi_uint_t ii;
embb_mtapi_log_trace("embb_mtapi_scheduler_initialize() called\n"); embb_mtapi_log_trace("embb_mtapi_scheduler_initialize() called\n");
...@@ -456,6 +480,10 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode( ...@@ -456,6 +480,10 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode(
that->worker_contexts = (embb_mtapi_thread_context_t*) that->worker_contexts = (embb_mtapi_thread_context_t*)
embb_mtapi_alloc_allocate( embb_mtapi_alloc_allocate(
sizeof(embb_mtapi_thread_context_t)*that->worker_count); sizeof(embb_mtapi_thread_context_t)*that->worker_count);
if (NULL == that->worker_contexts) {
return MTAPI_FALSE;
}
mtapi_boolean_t isinit = MTAPI_TRUE;
for (ii = 0; ii < that->worker_count; ii++) { for (ii = 0; ii < that->worker_count; ii++) {
unsigned int core_num = 0; unsigned int core_num = 0;
mtapi_uint_t ll = 0; mtapi_uint_t ll = 0;
...@@ -467,9 +495,12 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode( ...@@ -467,9 +495,12 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode(
} }
core_num++; core_num++;
} }
embb_mtapi_thread_context_initialize_with_node_worker_and_core( isinit &= embb_mtapi_thread_context_initialize_with_node_worker_and_core(
&that->worker_contexts[ii], node, ii, core_num); &that->worker_contexts[ii], node, ii, core_num);
} }
if (!isinit) {
return MTAPI_FALSE;
}
for (ii = 0; ii < that->worker_count; ii++) { for (ii = 0; ii < that->worker_count; ii++) {
if (MTAPI_FALSE == embb_mtapi_thread_context_start( if (MTAPI_FALSE == embb_mtapi_thread_context_start(
&that->worker_contexts[ii], that)) { &that->worker_contexts[ii], that)) {
...@@ -481,22 +512,24 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode( ...@@ -481,22 +512,24 @@ mtapi_boolean_t embb_mtapi_scheduler_initialize_with_mode(
} }
void embb_mtapi_scheduler_finalize(embb_mtapi_scheduler_t * that) { void embb_mtapi_scheduler_finalize(embb_mtapi_scheduler_t * that) {
mtapi_uint_t ii = 0; mtapi_uint_t ii;
embb_mtapi_log_trace("embb_mtapi_scheduler_finalize() called\n"); embb_mtapi_log_trace("embb_mtapi_scheduler_finalize() called\n");
assert(MTAPI_NULL != that); assert(MTAPI_NULL != that);
/* finalize all workers */ if (MTAPI_NULL != that->worker_contexts) {
for (ii = 0; ii < that->worker_count; ii++) { /* finalize all workers */
embb_mtapi_thread_context_stop(&that->worker_contexts[ii]); for (ii = 0; ii < that->worker_count; ii++) {
} embb_mtapi_thread_context_stop(&that->worker_contexts[ii]);
for (ii = 0; ii < that->worker_count; ii++) { }
embb_mtapi_thread_context_finalize(&that->worker_contexts[ii]); for (ii = 0; ii < that->worker_count; ii++) {
} embb_mtapi_thread_context_finalize(&that->worker_contexts[ii]);
}
that->worker_count = 0; that->worker_count = 0;
embb_mtapi_alloc_deallocate(that->worker_contexts); embb_mtapi_alloc_deallocate(that->worker_contexts);
that->worker_contexts = MTAPI_NULL; that->worker_contexts = MTAPI_NULL;
}
} }
embb_mtapi_scheduler_t * embb_mtapi_scheduler_new() { embb_mtapi_scheduler_t * embb_mtapi_scheduler_new() {
...@@ -506,6 +539,7 @@ embb_mtapi_scheduler_t * embb_mtapi_scheduler_new() { ...@@ -506,6 +539,7 @@ embb_mtapi_scheduler_t * embb_mtapi_scheduler_new() {
if (MTAPI_NULL != that) { if (MTAPI_NULL != that) {
if (MTAPI_FALSE == embb_mtapi_scheduler_initialize(that)) { if (MTAPI_FALSE == embb_mtapi_scheduler_initialize(that)) {
/* on error delete and return MTAPI_NULL */ /* on error delete and return MTAPI_NULL */
embb_mtapi_scheduler_finalize(that);
embb_mtapi_scheduler_delete(that); embb_mtapi_scheduler_delete(that);
return MTAPI_NULL; return MTAPI_NULL;
} }
......
...@@ -501,7 +501,6 @@ void mtapi_task_cancel( ...@@ -501,7 +501,6 @@ void mtapi_task_cancel(
if (embb_mtapi_task_pool_is_handle_valid(node->task_pool, task)) { if (embb_mtapi_task_pool_is_handle_valid(node->task_pool, task)) {
embb_mtapi_task_t* local_task = embb_mtapi_task_t* local_task =
embb_mtapi_task_pool_get_storage_for_handle(node->task_pool, task); embb_mtapi_task_pool_get_storage_for_handle(node->task_pool, task);
embb_mtapi_task_set_state(local_task, MTAPI_TASK_CANCELLED);
/* call plugin action cancel function */ /* call plugin action cancel function */
if (embb_mtapi_action_pool_is_handle_valid( if (embb_mtapi_action_pool_is_handle_valid(
...@@ -511,8 +510,14 @@ void mtapi_task_cancel( ...@@ -511,8 +510,14 @@ void mtapi_task_cancel(
node->action_pool, local_task->action); node->action_pool, local_task->action);
if (local_action->is_plugin_action) { if (local_action->is_plugin_action) {
local_action->plugin_task_cancel_function(task, &local_status); local_action->plugin_task_cancel_function(task, &local_status);
} else {
embb_mtapi_task_set_state(local_task, MTAPI_TASK_CANCELLED);
local_task->error_code = MTAPI_ERR_ACTION_CANCELLED;
local_status = MTAPI_SUCCESS;
} }
} else { } else {
embb_mtapi_task_set_state(local_task, MTAPI_TASK_CANCELLED);
local_task->error_code = MTAPI_ERR_ACTION_CANCELLED;
local_status = MTAPI_SUCCESS; local_status = MTAPI_SUCCESS;
} }
} else { } else {
......
...@@ -38,12 +38,13 @@ ...@@ -38,12 +38,13 @@
/* ---- CLASS MEMBERS ------------------------------------------------------ */ /* ---- CLASS MEMBERS ------------------------------------------------------ */
void embb_mtapi_thread_context_initialize_with_node_worker_and_core( mtapi_boolean_t embb_mtapi_thread_context_initialize_with_node_worker_and_core(
embb_mtapi_thread_context_t* that, embb_mtapi_thread_context_t* that,
embb_mtapi_node_t* node, embb_mtapi_node_t* node,
mtapi_uint_t worker_index, mtapi_uint_t worker_index,
mtapi_uint_t core_num) { mtapi_uint_t core_num) {
mtapi_uint_t ii; mtapi_uint_t ii;
mtapi_boolean_t result = MTAPI_TRUE;
assert(MTAPI_NULL != that); assert(MTAPI_NULL != that);
assert(MTAPI_NULL != node); assert(MTAPI_NULL != node);
...@@ -52,25 +53,55 @@ void embb_mtapi_thread_context_initialize_with_node_worker_and_core( ...@@ -52,25 +53,55 @@ void embb_mtapi_thread_context_initialize_with_node_worker_and_core(
that->worker_index = worker_index; that->worker_index = worker_index;
that->core_num = core_num; that->core_num = core_num;
that->priorities = node->attributes.max_priorities; that->priorities = node->attributes.max_priorities;
that->is_initialized = MTAPI_FALSE;
embb_atomic_store_int(&that->run, 0); embb_atomic_store_int(&that->run, 0);
that->queue = (embb_mtapi_task_queue_t**)embb_mtapi_alloc_allocate( that->queue = (embb_mtapi_task_queue_t**)embb_mtapi_alloc_allocate(
sizeof(embb_mtapi_task_queue_t)*that->priorities); sizeof(embb_mtapi_task_queue_t)*that->priorities);
that->private_queue = (embb_mtapi_task_queue_t**)embb_mtapi_alloc_allocate( if (that->queue == NULL) {
sizeof(embb_mtapi_task_queue_t)*that->priorities); that->private_queue = NULL;
return MTAPI_FALSE;
}
for (ii = 0; ii < that->priorities; ii++) { for (ii = 0; ii < that->priorities; ii++) {
that->queue[ii] = (embb_mtapi_task_queue_t*) that->queue[ii] = (embb_mtapi_task_queue_t*)
embb_mtapi_alloc_allocate(sizeof(embb_mtapi_task_queue_t)); embb_mtapi_alloc_allocate(sizeof(embb_mtapi_task_queue_t));
embb_mtapi_task_queue_initialize_with_capacity( if (that->queue[ii] != NULL) {
that->queue[ii], node->attributes.queue_limit); embb_mtapi_task_queue_initialize_with_capacity(
that->queue[ii], node->attributes.queue_limit);
} else {
result = MTAPI_FALSE;
}
}
if (!result) {
return MTAPI_FALSE;
}
that->private_queue = (embb_mtapi_task_queue_t**)embb_mtapi_alloc_allocate(
sizeof(embb_mtapi_task_queue_t)*that->priorities);
if (that->private_queue == NULL) {
return MTAPI_FALSE;
}
for (ii = 0; ii < that->priorities; ii++) {
that->private_queue[ii] = (embb_mtapi_task_queue_t*) that->private_queue[ii] = (embb_mtapi_task_queue_t*)
embb_mtapi_alloc_allocate(sizeof(embb_mtapi_task_queue_t)); embb_mtapi_alloc_allocate(sizeof(embb_mtapi_task_queue_t));
embb_mtapi_task_queue_initialize_with_capacity( if (that->private_queue[ii] != NULL) {
that->private_queue[ii], node->attributes.queue_limit); embb_mtapi_task_queue_initialize_with_capacity(
that->private_queue[ii], node->attributes.queue_limit);
} else {
result = MTAPI_FALSE;
}
}
if (!result) {
return MTAPI_FALSE;
} }
embb_mutex_init(&that->work_available_mutex, EMBB_MUTEX_PLAIN); embb_mutex_init(&that->work_available_mutex, EMBB_MUTEX_PLAIN);
embb_condition_init(&that->work_available); embb_condition_init(&that->work_available);
embb_atomic_store_int(&that->is_sleeping, 0); embb_atomic_store_int(&that->is_sleeping, 0);
that->is_initialized = MTAPI_TRUE;
return MTAPI_TRUE;
} }
mtapi_boolean_t embb_mtapi_thread_context_start( mtapi_boolean_t embb_mtapi_thread_context_start(
...@@ -126,22 +157,37 @@ void embb_mtapi_thread_context_finalize(embb_mtapi_thread_context_t* that) { ...@@ -126,22 +157,37 @@ void embb_mtapi_thread_context_finalize(embb_mtapi_thread_context_t* that) {
embb_mtapi_log_trace("embb_mtapi_thread_context_finalize() called\n"); embb_mtapi_log_trace("embb_mtapi_thread_context_finalize() called\n");
embb_condition_destroy(&that->work_available); if (that->is_initialized) {
embb_mutex_destroy(&that->work_available_mutex); embb_condition_destroy(&that->work_available);
embb_mutex_destroy(&that->work_available_mutex);
}
for (ii = 0; ii < that->priorities; ii++) { if (that->queue != NULL) {
embb_mtapi_task_queue_finalize(that->queue[ii]); for (ii = 0; ii < that->priorities; ii++) {
embb_mtapi_alloc_deallocate(that->queue[ii]); if (that->queue[ii] != NULL) {
that->queue[ii] = MTAPI_NULL; embb_mtapi_task_queue_finalize(that->queue[ii]);
embb_mtapi_task_queue_finalize(that->private_queue[ii]); embb_mtapi_alloc_deallocate(that->queue[ii]);
embb_mtapi_alloc_deallocate(that->private_queue[ii]); that->queue[ii] = MTAPI_NULL;
that->private_queue[ii] = MTAPI_NULL; }
}
embb_mtapi_alloc_deallocate(that->queue);
that->queue = MTAPI_NULL;
} }
embb_mtapi_alloc_deallocate(that->queue);
that->queue = MTAPI_NULL; if (that->private_queue != NULL) {
embb_mtapi_alloc_deallocate(that->private_queue); for (ii = 0; ii < that->priorities; ii++) {
that->private_queue = MTAPI_NULL; if (that->private_queue[ii] != NULL) {
embb_mtapi_task_queue_finalize(that->private_queue[ii]);
embb_mtapi_alloc_deallocate(that->private_queue[ii]);
that->private_queue[ii] = MTAPI_NULL;
}
}
embb_mtapi_alloc_deallocate(that->private_queue);
that->private_queue = MTAPI_NULL;
}
that->priorities = 0; that->priorities = 0;
that->is_initialized = MTAPI_FALSE;
that->node = MTAPI_NULL; that->node = MTAPI_NULL;
} }
......
...@@ -67,6 +67,7 @@ struct embb_mtapi_thread_context_struct { ...@@ -67,6 +67,7 @@ struct embb_mtapi_thread_context_struct {
mtapi_uint_t core_num; mtapi_uint_t core_num;
embb_atomic_int run; embb_atomic_int run;
mtapi_status_t status; mtapi_status_t status;
mtapi_boolean_t is_initialized;
}; };
#include <embb_mtapi_thread_context_t_fwd.h> #include <embb_mtapi_thread_context_t_fwd.h>
...@@ -74,8 +75,9 @@ struct embb_mtapi_thread_context_struct { ...@@ -74,8 +75,9 @@ struct embb_mtapi_thread_context_struct {
/** /**
* Constructor using attributes from node and a given core number. * Constructor using attributes from node and a given core number.
* \memberof embb_mtapi_thread_context_struct * \memberof embb_mtapi_thread_context_struct
* \returns MTAPI_TRUE if successful, MTAPI_FALSE on error
*/ */
void embb_mtapi_thread_context_initialize_with_node_worker_and_core( mtapi_boolean_t embb_mtapi_thread_context_initialize_with_node_worker_and_core(
embb_mtapi_thread_context_t* that, embb_mtapi_thread_context_t* that,
embb_mtapi_node_t* node, embb_mtapi_node_t* node,
mtapi_uint_t worker_index, mtapi_uint_t worker_index,
......
...@@ -71,8 +71,10 @@ void embb_mtapi_network_finalize() { ...@@ -71,8 +71,10 @@ void embb_mtapi_network_finalize() {
} }
enum embb_mtapi_network_operation_enum { enum embb_mtapi_network_operation_enum {
EMBB_MTAPI_NETWORK_START_TASK, EMBB_MTAPI_NETWORK_START_TASK = 0x01AFFE01,
EMBB_MTAPI_NETWORK_RETURN_RESULT EMBB_MTAPI_NETWORK_RETURN_RESULT = 0x02AFFE02,
EMBB_MTAPI_NETWORK_RETURN_FAILURE = 0x03AFFE03,
EMBB_MTAPI_NETWORK_CANCEL_TASK = 0x04AFFE04
}; };
struct embb_mtapi_network_plugin_struct { struct embb_mtapi_network_plugin_struct {
...@@ -84,6 +86,8 @@ struct embb_mtapi_network_plugin_struct { ...@@ -84,6 +86,8 @@ struct embb_mtapi_network_plugin_struct {
embb_mutex_t send_mutex; embb_mutex_t send_mutex;
embb_mtapi_network_buffer_t send_buffer; embb_mtapi_network_buffer_t send_buffer;
embb_mtapi_network_buffer_t recv_buffer;
}; };
typedef struct embb_mtapi_network_plugin_struct embb_mtapi_network_plugin_t; typedef struct embb_mtapi_network_plugin_struct embb_mtapi_network_plugin_t;
...@@ -112,12 +116,40 @@ struct embb_mtapi_network_task_struct { ...@@ -112,12 +116,40 @@ struct embb_mtapi_network_task_struct {
typedef struct embb_mtapi_network_task_struct embb_mtapi_network_task_t; typedef struct embb_mtapi_network_task_struct embb_mtapi_network_task_t;
static void embb_mtapi_network_return_failure(
int32_t remote_task_id,
int32_t remote_task_tag,
mtapi_status_t status,
embb_mtapi_network_socket_t * socket,
embb_mtapi_network_buffer_t * buffer) {
embb_mtapi_network_buffer_clear(buffer);
// packet size
embb_mtapi_network_buffer_push_back_int32(
buffer, 16);
// operation
embb_mtapi_network_buffer_push_back_int32(
buffer, EMBB_MTAPI_NETWORK_RETURN_FAILURE);
// task handle
embb_mtapi_network_buffer_push_back_int32(
buffer, remote_task_id);
embb_mtapi_network_buffer_push_back_int32(
buffer, remote_task_tag);
// status
embb_mtapi_network_buffer_push_back_int32(
buffer, (int32_t)status);
embb_mtapi_network_socket_sendbuffer(
socket, buffer);
}
static void embb_mtapi_network_task_complete( static void embb_mtapi_network_task_complete(
MTAPI_IN mtapi_task_hndl_t task, MTAPI_IN mtapi_task_hndl_t task,
MTAPI_OUT mtapi_status_t* status) { MTAPI_OUT mtapi_status_t* status) {
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
int err;
EMBB_UNUSED_IN_RELEASE(err);
if (embb_mtapi_node_is_initialized()) { if (embb_mtapi_node_is_initialized()) {
embb_mtapi_node_t * node = embb_mtapi_node_get_instance(); embb_mtapi_node_t * node = embb_mtapi_node_get_instance();
...@@ -138,37 +170,69 @@ static void embb_mtapi_network_task_complete( ...@@ -138,37 +170,69 @@ static void embb_mtapi_network_task_complete(
(embb_mtapi_network_task_t*)local_task->attributes.user_data; (embb_mtapi_network_task_t*)local_task->attributes.user_data;
embb_mtapi_network_buffer_t * send_buf = &plugin->send_buffer; embb_mtapi_network_buffer_t * send_buf = &plugin->send_buffer;
embb_atomic_memory_barrier();
local_task->attributes.complete_func = NULL;
embb_atomic_memory_barrier();
// serialize sending of results // serialize sending of results
embb_mutex_lock(&plugin->send_mutex); embb_mutex_lock(&plugin->send_mutex);
embb_mtapi_network_buffer_clear(send_buf); embb_mtapi_network_buffer_clear(send_buf);
// operation is "return result" if (local_task->error_code == MTAPI_SUCCESS) {
err = embb_mtapi_network_buffer_push_back_int8( // actual counts bytes actually put into the buffer
send_buf, EMBB_MTAPI_NETWORK_RETURN_RESULT); int actual = 0;
assert(err == 1); // expected counts bytes we intended to put into the buffer
// remote task id int expected =
err = embb_mtapi_network_buffer_push_back_int32( 4 + // operation
send_buf, network_task->remote_task_id); 4 + 4 + // remote task handle
assert(err == 4); 4 + // status
err = embb_mtapi_network_buffer_push_back_int32( 4 + (int)local_task->result_size; // result buffer
send_buf, network_task->remote_task_tag);
assert(err == 4); // packet size
// status actual += embb_mtapi_network_buffer_push_back_int32(
err = embb_mtapi_network_buffer_push_back_int32( send_buf, expected);
send_buf, local_task->error_code); expected += 4;
assert(err == 4);
// result size // operation is "return result"
err = embb_mtapi_network_buffer_push_back_int32( actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)local_task->result_size); send_buf, EMBB_MTAPI_NETWORK_RETURN_RESULT);
assert(err == 4);
err = embb_mtapi_network_buffer_push_back_rawdata( // remote task id
send_buf, (int32_t)local_task->result_size, actual += embb_mtapi_network_buffer_push_back_int32(
local_task->result_buffer); send_buf, network_task->remote_task_id);
assert(err == (int)local_task->result_size); actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, network_task->remote_task_tag);
// status
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, local_task->error_code);
err = embb_mtapi_network_socket_sendbuffer( // result size
&network_task->socket, send_buf); actual += embb_mtapi_network_buffer_push_back_int32(
assert(err == send_buf->size); send_buf, (int32_t)local_task->result_size);
actual += embb_mtapi_network_buffer_push_back_rawdata(
send_buf, (int32_t)local_task->result_size,
local_task->result_buffer);
if (expected == actual) {
int sent = embb_mtapi_network_socket_sendbuffer(
&network_task->socket, send_buf);
assert(sent == send_buf->size);
EMBB_UNUSED_IN_RELEASE(sent);
} else {
embb_mtapi_network_return_failure(
network_task->remote_task_id,
network_task->remote_task_tag,
MTAPI_ERR_UNKNOWN,
&network_task->socket, send_buf);
}
} else {
embb_mtapi_network_return_failure(
network_task->remote_task_id,
network_task->remote_task_tag,
local_task->error_code,
&network_task->socket, send_buf);
}
// sending done // sending done
embb_mutex_unlock(&plugin->send_mutex); embb_mutex_unlock(&plugin->send_mutex);
...@@ -177,6 +241,14 @@ static void embb_mtapi_network_task_complete( ...@@ -177,6 +241,14 @@ static void embb_mtapi_network_task_complete(
embb_free((void*)local_task->arguments); embb_free((void*)local_task->arguments);
embb_free(local_task->result_buffer); embb_free(local_task->result_buffer);
void * data = local_task->attributes.user_data;
embb_atomic_memory_barrier();
local_task->attributes.user_data = NULL;
embb_atomic_memory_barrier();
embb_free(data);
local_status = MTAPI_SUCCESS; local_status = MTAPI_SUCCESS;
} }
} }
...@@ -185,15 +257,326 @@ static void embb_mtapi_network_task_complete( ...@@ -185,15 +257,326 @@ static void embb_mtapi_network_task_complete(
mtapi_status_set(status, local_status); mtapi_status_set(status, local_status);
} }
static mtapi_status_t embb_mtapi_network_handle_start_task(
embb_mtapi_network_socket_t * socket,
embb_mtapi_network_buffer_t * buffer,
int packet_size) {
int32_t domain_id;
int32_t job_id;
int32_t results_size;
void * results;
int err;
EMBB_UNUSED_IN_RELEASE(err);
int32_t arguments_size;
int32_t remote_task_id;
int32_t remote_task_tag;
mtapi_uint_t priority = 0;
mtapi_job_hndl_t job_hndl;
mtapi_task_attributes_t task_attr;
void * arguments;
mtapi_task_complete_function_t func = embb_mtapi_network_task_complete;
void * func_void;
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
// check if we have at least 28 bytes
if (packet_size >= 28) {
// domain id
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &domain_id);
assert(err == 4);
// job id
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &job_id);
assert(err == 4);
// priority
err = embb_mtapi_network_buffer_pop_front_int32(
buffer, (int32_t*)&priority);
assert(err == 4);
// remote task handle
err = embb_mtapi_network_buffer_pop_front_int32(
buffer, &remote_task_id);
assert(err == 4);
err = embb_mtapi_network_buffer_pop_front_int32(
buffer, &remote_task_tag);
assert(err == 4);
// result size
err = embb_mtapi_network_buffer_pop_front_int32(buffer,
&results_size);
assert(err == 4);
// arguments size
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &arguments_size);
assert(err == 4);
embb_mtapi_network_task_t * network_task =
(embb_mtapi_network_task_t*)embb_alloc(
sizeof(embb_mtapi_network_task_t));
if (network_task == NULL) {
embb_mtapi_network_return_failure(
remote_task_id, remote_task_tag, MTAPI_ERR_UNKNOWN,
socket, buffer);
return MTAPI_ERR_UNKNOWN;
}
network_task->remote_task_id = remote_task_id;
network_task->remote_task_tag = remote_task_tag;
// check packet_size again
if (packet_size == 28 + arguments_size) {
// allocate buffers
results = embb_alloc((size_t)results_size);
if (results == NULL) {
embb_mtapi_network_return_failure(
remote_task_id, remote_task_tag, MTAPI_ERR_UNKNOWN,
socket, buffer);
return MTAPI_ERR_UNKNOWN;
}
arguments = embb_alloc((size_t)arguments_size);
if (arguments == NULL) {
embb_free(results);
embb_mtapi_network_return_failure(
remote_task_id, remote_task_tag, MTAPI_ERR_UNKNOWN,
socket, buffer);
return MTAPI_ERR_UNKNOWN;
}
// arguments
err = embb_mtapi_network_buffer_pop_front_rawdata(
buffer, arguments_size, arguments);
assert(err == arguments_size);
network_task->socket = *socket;
mtapi_taskattr_init(&task_attr, &local_status);
assert(local_status == MTAPI_SUCCESS);
mtapi_taskattr_set(&task_attr, MTAPI_TASK_USER_DATA,
(void*)network_task, 0, &local_status);
assert(local_status == MTAPI_SUCCESS);
mtapi_boolean_t task_detached = MTAPI_TRUE;
mtapi_taskattr_set(&task_attr, MTAPI_TASK_DETACHED,
(void*)&task_detached, sizeof(mtapi_boolean_t), &local_status);
assert(local_status == MTAPI_SUCCESS);
mtapi_taskattr_set(&task_attr, MTAPI_TASK_PRIORITY,
(void*)&priority, sizeof(mtapi_uint_t), &local_status);
assert(local_status == MTAPI_SUCCESS);
memcpy(&func_void, &func, sizeof(void*));
mtapi_taskattr_set(&task_attr, MTAPI_TASK_COMPLETE_FUNCTION,
func_void, 0, &local_status);
assert(local_status == MTAPI_SUCCESS);
job_hndl = mtapi_job_get((mtapi_job_id_t)job_id,
(mtapi_domain_t)domain_id, &local_status);
if (local_status == MTAPI_SUCCESS) {
mtapi_task_start(
MTAPI_TASK_ID_NONE, job_hndl,
arguments, (mtapi_size_t)arguments_size,
results, (mtapi_size_t)results_size,
&task_attr, MTAPI_GROUP_NONE,
&local_status);
}
if (local_status != MTAPI_SUCCESS) {
embb_free(arguments);
embb_free(results);
embb_mtapi_network_return_failure(
remote_task_id, remote_task_tag, local_status, socket, buffer);
}
}
}
return local_status;
}
static mtapi_status_t embb_mtapi_network_handle_return_result(
embb_mtapi_network_buffer_t * buffer,
int packet_size) {
int32_t task_status;
int32_t task_id;
int32_t task_tag;
int32_t results_size;
int err;
EMBB_UNUSED_IN_RELEASE(err);
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
if (embb_mtapi_node_is_initialized()) {
embb_mtapi_node_t * node = embb_mtapi_node_get_instance();
mtapi_task_hndl_t task;
// do we have at least 16 bytes?
if (packet_size >= 16) {
// local task id
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &task_id);
assert(err == 4);
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &task_tag);
assert(err == 4);
// task status
err = embb_mtapi_network_buffer_pop_front_int32(
buffer, &task_status);
assert(err == 4);
// result size
err = embb_mtapi_network_buffer_pop_front_int32(
buffer, &results_size);
assert(err == 4);
// check packet_size again
if (packet_size == 16 + results_size) {
task.id = (mtapi_task_id_t)task_id;
task.tag = (mtapi_uint_t)task_tag;
if (embb_mtapi_task_pool_is_handle_valid(node->task_pool, task)) {
embb_mtapi_task_t * local_task =
embb_mtapi_task_pool_get_storage_for_handle(
node->task_pool, task);
if (embb_mtapi_action_pool_is_handle_valid(
node->action_pool, local_task->action)) {
embb_mtapi_action_t * local_action =
embb_mtapi_action_pool_get_storage_for_handle(
node->action_pool, local_task->action);
/* not needed right now
embb_mtapi_network_action_t * network_action =
(embb_mtapi_network_action_t*)local_action->plugin_data;*/
err = embb_mtapi_network_buffer_pop_front_rawdata(
buffer, results_size, local_task->result_buffer);
assert(err == results_size);
local_task->error_code = (mtapi_status_t)task_status;
embb_atomic_store_int(&local_task->state, MTAPI_TASK_COMPLETED);
embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1);
/* is task associated with a group? */
if (embb_mtapi_group_pool_is_handle_valid(
node->group_pool, local_task->group)) {
embb_mtapi_group_t* local_group =
embb_mtapi_group_pool_get_storage_for_handle(
node->group_pool, local_task->group);
embb_mtapi_task_queue_push(&local_group->queue, local_task);
}
local_status = MTAPI_SUCCESS;
}
}
}
}
}
return local_status;
}
static mtapi_status_t embb_mtapi_network_handle_return_failure(
embb_mtapi_network_buffer_t * buffer,
int packet_size) {
int32_t task_status;
int32_t task_id;
int32_t task_tag;
int err;
EMBB_UNUSED_IN_RELEASE(err);
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
if (embb_mtapi_node_is_initialized()) {
embb_mtapi_node_t * node = embb_mtapi_node_get_instance();
mtapi_task_hndl_t task;
// do we have 12 bytes?
if (packet_size == 12) {
// local task id
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &task_id);
assert(err == 4);
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &task_tag);
assert(err == 4);
// task status
err = embb_mtapi_network_buffer_pop_front_int32(
buffer, &task_status);
assert(err == 4);
task.id = (mtapi_task_id_t)task_id;
task.tag = (mtapi_uint_t)task_tag;
if (embb_mtapi_task_pool_is_handle_valid(node->task_pool, task)) {
embb_mtapi_task_t * local_task =
embb_mtapi_task_pool_get_storage_for_handle(
node->task_pool, task);
if (embb_mtapi_action_pool_is_handle_valid(
node->action_pool, local_task->action)) {
embb_mtapi_action_t * local_action =
embb_mtapi_action_pool_get_storage_for_handle(
node->action_pool, local_task->action);
embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1);
local_task->error_code = (mtapi_status_t)task_status;
if (MTAPI_ERR_ACTION_CANCELLED == task_status) {
embb_atomic_store_int(&local_task->state, MTAPI_TASK_CANCELLED);
} else {
embb_atomic_store_int(&local_task->state, MTAPI_TASK_ERROR);
}
/* is task associated with a group? */
if (embb_mtapi_group_pool_is_handle_valid(
node->group_pool, local_task->group)) {
embb_mtapi_group_t* local_group =
embb_mtapi_group_pool_get_storage_for_handle(
node->group_pool, local_task->group);
embb_mtapi_task_queue_push(&local_group->queue, local_task);
}
local_status = MTAPI_SUCCESS;
}
}
}
}
return local_status;
}
static mtapi_status_t embb_mtapi_network_handle_cancel_task(
embb_mtapi_network_buffer_t * buffer,
int packet_size) {
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
int32_t remote_task_id;
int32_t remote_task_tag;
int err;
EMBB_UNUSED_IN_RELEASE(err);
// do we have 8 bytes?
if (packet_size == 8) {
// get task handle
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &remote_task_id);
assert(err == 4);
err = embb_mtapi_network_buffer_pop_front_int32(buffer, &remote_task_tag);
assert(err == 4);
if (embb_mtapi_node_is_initialized()) {
embb_mtapi_node_t * node = embb_mtapi_node_get_instance();
// search for task to cancel
for (mtapi_uint_t ii = 0; ii < node->attributes.max_tasks; ii++) {
embb_mtapi_task_t * task = &node->task_pool->storage[ii];
// is this our task?
if (embb_mtapi_network_task_complete ==
task->attributes.complete_func) {
embb_mtapi_network_task_t * network_task =
(embb_mtapi_network_task_t*)task->attributes.user_data;
// is this task the one matching the given remote task?
if (remote_task_id == network_task->remote_task_id &&
remote_task_tag == network_task->remote_task_tag) {
mtapi_task_cancel(task->handle, &local_status);
break;
}
}
}
}
}
return local_status;
}
static int embb_mtapi_network_thread(void * args) { static int embb_mtapi_network_thread(void * args) {
embb_mtapi_network_plugin_t * plugin = &embb_mtapi_network_plugin; embb_mtapi_network_plugin_t * plugin = &embb_mtapi_network_plugin;
embb_mtapi_network_buffer_t buffer; embb_mtapi_network_buffer_t * buffer = &plugin->recv_buffer;
int err; int err;
EMBB_UNUSED(args); EMBB_UNUSED(args);
embb_mtapi_network_buffer_initialize(&buffer, (int)plugin->buffer_size);
while (embb_atomic_load_int(&plugin->run)) { while (embb_atomic_load_int(&plugin->run)) {
err = embb_mtapi_network_socket_select( err = embb_mtapi_network_socket_select(
plugin->sockets, plugin->socket_count, 100); plugin->sockets, plugin->socket_count, 100);
...@@ -208,197 +591,52 @@ static int embb_mtapi_network_thread(void * args) { ...@@ -208,197 +591,52 @@ static int embb_mtapi_network_thread(void * args) {
plugin->socket_count++; plugin->socket_count++;
} }
} else if (0 < err) { } else if (0 < err) {
int32_t domain_id; int32_t operation;
int32_t job_id; int32_t packet_size;
int32_t results_size;
void * results;
int8_t operation;
embb_mtapi_network_socket_t * socket = &plugin->sockets[err]; embb_mtapi_network_socket_t * socket = &plugin->sockets[err];
embb_mtapi_network_buffer_clear(&buffer); embb_mtapi_network_buffer_clear(buffer);
err = embb_mtapi_network_socket_recvbuffer_sized( err = embb_mtapi_network_socket_recvbuffer_sized(
socket, &buffer, 1); socket, buffer, 4);
if (err == 0) { if (err == 4) {
// there was some socket error, ignore
continue;
}
assert(err == 1);
err = embb_mtapi_network_buffer_pop_front_int8(
&buffer, &operation);
assert(err == 1);
embb_mtapi_network_buffer_clear(&buffer);
if (operation == EMBB_MTAPI_NETWORK_START_TASK) {
int32_t arguments_size;
mtapi_uint_t priority = 0;
mtapi_job_hndl_t job_hndl;
mtapi_task_attributes_t task_attr;
void * arguments;
mtapi_task_complete_function_t func = embb_mtapi_network_task_complete;
void * func_void;
embb_mtapi_network_task_t * network_task =
(embb_mtapi_network_task_t*)embb_alloc(
sizeof(embb_mtapi_network_task_t));
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
err = embb_mtapi_network_socket_recvbuffer_sized(
socket, &buffer, 28);
assert(err == 28);
// domain id
err = embb_mtapi_network_buffer_pop_front_int32(&buffer, &domain_id);
assert(err == 4);
// job id
err = embb_mtapi_network_buffer_pop_front_int32(&buffer, &job_id);
assert(err == 4);
// priority
err = embb_mtapi_network_buffer_pop_front_int32(
&buffer, (int32_t*)&priority);
assert(err == 4);
// remote task handle
err = embb_mtapi_network_buffer_pop_front_int32( err = embb_mtapi_network_buffer_pop_front_int32(
&buffer, &network_task->remote_task_id); buffer, &packet_size);
assert(err == 4);
err = embb_mtapi_network_buffer_pop_front_int32(
&buffer, &network_task->remote_task_tag);
assert(err == 4);
// result size
err = embb_mtapi_network_buffer_pop_front_int32(&buffer,
&results_size);
assert(err == 4);
results = embb_alloc((size_t)results_size);
assert(results != NULL);
// arguments size
embb_mtapi_network_buffer_pop_front_int32(&buffer, &arguments_size);
assert(err == 4); assert(err == 4);
arguments = embb_alloc((size_t)arguments_size);
assert(arguments != NULL);
embb_mtapi_network_buffer_clear(&buffer); embb_mtapi_network_buffer_clear(buffer);
// arguments
err = embb_mtapi_network_socket_recvbuffer_sized( err = embb_mtapi_network_socket_recvbuffer_sized(
socket, &buffer, arguments_size); socket, buffer, packet_size);
assert(err == arguments_size); if (err == packet_size) {
err = embb_mtapi_network_buffer_pop_front_rawdata(
&buffer, arguments_size, arguments);
assert(err == arguments_size);
embb_mtapi_network_buffer_clear(&buffer);
network_task->socket = *socket;
mtapi_taskattr_init(&task_attr, &local_status);
assert(local_status == MTAPI_SUCCESS);
mtapi_taskattr_set(&task_attr, MTAPI_TASK_USER_DATA,
(void*)network_task, 0, &local_status);
assert(local_status == MTAPI_SUCCESS);
mtapi_boolean_t task_detached = MTAPI_TRUE;
mtapi_taskattr_set(&task_attr, MTAPI_TASK_DETACHED,
(void*)&task_detached, sizeof(mtapi_boolean_t), &local_status);
assert(local_status == MTAPI_SUCCESS);
mtapi_taskattr_set(&task_attr, MTAPI_TASK_PRIORITY,
(void*)&priority, sizeof(mtapi_uint_t), &local_status);
assert(local_status == MTAPI_SUCCESS);
memcpy(&func_void, &func, sizeof(void*));
mtapi_taskattr_set(&task_attr, MTAPI_TASK_COMPLETE_FUNCTION,
func_void, 0, &local_status);
assert(local_status == MTAPI_SUCCESS);
job_hndl = mtapi_job_get((mtapi_job_id_t)job_id,
(mtapi_domain_t)domain_id, &local_status);
assert(local_status == MTAPI_SUCCESS);
mtapi_task_start(
MTAPI_TASK_ID_NONE, job_hndl,
arguments, (mtapi_size_t)arguments_size,
results, (mtapi_size_t)results_size,
&task_attr, MTAPI_GROUP_NONE,
&local_status);
assert(local_status == MTAPI_SUCCESS);
// send back result of task creation
//embb_mtapi_network_buffer_push_back_int32(
// &buffer, local_status);
//embb_mtapi_network_socket_sendbuffer(
// socket, &buffer);
embb_mtapi_network_buffer_clear(&buffer);
} else if (operation == EMBB_MTAPI_NETWORK_RETURN_RESULT) {
int task_status;
int task_id;
int task_tag;
embb_mtapi_network_buffer_clear(&buffer);
if (embb_mtapi_node_is_initialized()) {
embb_mtapi_node_t * node = embb_mtapi_node_get_instance();
mtapi_task_hndl_t task;
err = embb_mtapi_network_socket_recvbuffer_sized(
socket, &buffer, 16);
assert(err == 16);
// local task id
err = embb_mtapi_network_buffer_pop_front_int32(&buffer, &task_id);
assert(err == 4);
err = embb_mtapi_network_buffer_pop_front_int32(&buffer, &task_tag);
assert(err == 4);
// task status
err = embb_mtapi_network_buffer_pop_front_int32( err = embb_mtapi_network_buffer_pop_front_int32(
&buffer, &task_status); buffer, &operation);
assert(err == 4); assert(err == 4);
// result size packet_size -= 4;
err = embb_mtapi_network_buffer_pop_front_int32(
&buffer, &results_size); switch (operation) {
assert(err == 4); case EMBB_MTAPI_NETWORK_START_TASK:
embb_mtapi_network_handle_start_task(socket, buffer, packet_size);
embb_mtapi_network_buffer_clear(&buffer); break;
case EMBB_MTAPI_NETWORK_RETURN_RESULT:
err = embb_mtapi_network_socket_recvbuffer_sized( embb_mtapi_network_handle_return_result(buffer, packet_size);
socket, &buffer, results_size); break;
assert(err == results_size); case EMBB_MTAPI_NETWORK_RETURN_FAILURE:
embb_mtapi_network_handle_return_failure(buffer, packet_size);
task.id = (mtapi_task_id_t)task_id; break;
task.tag = (mtapi_uint_t)task_tag; case EMBB_MTAPI_NETWORK_CANCEL_TASK:
embb_mtapi_network_handle_cancel_task(buffer, packet_size);
if (embb_mtapi_task_pool_is_handle_valid(node->task_pool, task)) { break;
embb_mtapi_task_t * local_task = default:
embb_mtapi_task_pool_get_storage_for_handle( // invalid, ignore
node->task_pool, task); break;
if (embb_mtapi_action_pool_is_handle_valid(
node->action_pool, local_task->action)) {
embb_mtapi_action_t * local_action =
embb_mtapi_action_pool_get_storage_for_handle(
node->action_pool, local_task->action);
/* not needed right now
embb_mtapi_network_action_t * network_action =
(embb_mtapi_network_action_t*)local_action->plugin_data;*/
err = embb_mtapi_network_buffer_pop_front_rawdata(
&buffer, results_size, local_task->result_buffer);
assert(err == results_size);
local_task->error_code = (mtapi_status_t)task_status;
embb_atomic_store_int(&local_task->state, MTAPI_TASK_COMPLETED);
embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1);
/* is task associated with a group? */
if (embb_mtapi_group_pool_is_handle_valid(
node->group_pool, local_task->group)) {
embb_mtapi_group_t* local_group =
embb_mtapi_group_pool_get_storage_for_handle(
node->group_pool, local_task->group);
embb_mtapi_task_queue_push(&local_group->queue, local_task);
}
}
} }
} }
} }
embb_mtapi_network_buffer_clear(buffer);
} }
} }
embb_mtapi_network_buffer_finalize(&buffer);
return EMBB_SUCCESS; return EMBB_SUCCESS;
} }
...@@ -408,42 +646,106 @@ void mtapi_network_plugin_initialize( ...@@ -408,42 +646,106 @@ void mtapi_network_plugin_initialize(
MTAPI_IN mtapi_uint16_t max_connections, MTAPI_IN mtapi_uint16_t max_connections,
MTAPI_IN mtapi_size_t buffer_size, MTAPI_IN mtapi_size_t buffer_size,
MTAPI_OUT mtapi_status_t* status) { MTAPI_OUT mtapi_status_t* status) {
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN;
embb_mtapi_network_plugin_t * plugin = &embb_mtapi_network_plugin; embb_mtapi_network_plugin_t * plugin = &embb_mtapi_network_plugin;
int err; int err;
mtapi_status_set(status, MTAPI_ERR_UNKNOWN);
plugin->socket_count = 0;
plugin->buffer_size = 0;
plugin->sockets = NULL;
embb_atomic_store_int(&plugin->run, 0);
err = embb_mtapi_network_initialize(); err = embb_mtapi_network_initialize();
if (err) { if (0 == err) return;
embb_atomic_store_int(&plugin->run, 1);
plugin->buffer_size = buffer_size; err = embb_mtapi_network_buffer_initialize(
&plugin->recv_buffer, (int)buffer_size);
plugin->socket_count = 1; if (0 == err) {
// 1 listening socket and max_connections connections embb_mtapi_network_finalize();
// (2 sockets each if local) return;
plugin->sockets = (embb_mtapi_network_socket_t*)embb_alloc(
sizeof(embb_mtapi_network_socket_t) * (1 + max_connections * 2));
embb_mtapi_network_buffer_initialize(
&plugin->send_buffer, (int)plugin->buffer_size);
embb_mutex_init(&plugin->send_mutex, 0);
if (NULL != plugin->sockets) {
err = embb_mtapi_network_socket_initialize(&plugin->sockets[0]);
if (err) {
err = embb_mtapi_network_socket_bind_and_listen(
&plugin->sockets[0], host, port, max_connections);
if (err) {
err = embb_thread_create(
&plugin->thread, NULL, embb_mtapi_network_thread, NULL);
if (EMBB_SUCCESS == err) {
local_status = MTAPI_SUCCESS;
}
}
}
}
} }
mtapi_status_set(status, local_status); err = embb_mtapi_network_buffer_initialize(
&plugin->send_buffer, (int)buffer_size);
if (0 == err) {
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
embb_mtapi_network_finalize();
return;
}
plugin->buffer_size = buffer_size;
// 1 listening socket and max_connections connections
// (2 sockets each if local)
plugin->sockets = (embb_mtapi_network_socket_t*)embb_alloc(
sizeof(embb_mtapi_network_socket_t) * (1 + max_connections * 2));
if (NULL == plugin->sockets) {
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_mtapi_network_finalize();
return;
}
err = embb_mutex_init(&plugin->send_mutex, 0);
if (EMBB_SUCCESS != err) {
embb_free(plugin->sockets);
plugin->sockets = NULL;
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_mtapi_network_finalize();
return;
}
err = embb_mtapi_network_socket_initialize(&plugin->sockets[0]);
if (0 == err) {
embb_mutex_destroy(&plugin->send_mutex);
embb_free(plugin->sockets);
plugin->sockets = NULL;
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_mtapi_network_finalize();
return;
}
plugin->socket_count = 1;
err = embb_mtapi_network_socket_bind_and_listen(
&plugin->sockets[0], host, port, max_connections);
if (0 == err) {
embb_mtapi_network_socket_finalize(&plugin->sockets[0]);
plugin->socket_count = 0;
embb_mutex_destroy(&plugin->send_mutex);
embb_free(plugin->sockets);
plugin->sockets = NULL;
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_mtapi_network_finalize();
return;
}
embb_atomic_store_int(&plugin->run, 1);
err = embb_thread_create(
&plugin->thread, NULL, embb_mtapi_network_thread, NULL);
if (EMBB_SUCCESS != err) {
embb_atomic_store_int(&plugin->run, 0);
embb_mtapi_network_socket_finalize(&plugin->sockets[0]);
plugin->socket_count = 0;
embb_mutex_destroy(&plugin->send_mutex);
embb_free(plugin->sockets);
plugin->sockets = NULL;
embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
plugin->buffer_size = 0;
embb_mtapi_network_finalize();
return;
}
mtapi_status_set(status, MTAPI_SUCCESS);
} }
void mtapi_network_plugin_finalize( void mtapi_network_plugin_finalize(
...@@ -458,6 +760,8 @@ void mtapi_network_plugin_finalize( ...@@ -458,6 +760,8 @@ void mtapi_network_plugin_finalize(
embb_mutex_destroy(&plugin->send_mutex); embb_mutex_destroy(&plugin->send_mutex);
embb_mtapi_network_buffer_finalize(&plugin->send_buffer); embb_mtapi_network_buffer_finalize(&plugin->send_buffer);
embb_mtapi_network_buffer_finalize(&plugin->recv_buffer);
embb_mtapi_network_socket_finalize(&plugin->sockets[0]); embb_mtapi_network_socket_finalize(&plugin->sockets[0]);
embb_free(plugin->sockets); embb_free(plugin->sockets);
embb_mtapi_network_finalize(); embb_mtapi_network_finalize();
...@@ -468,9 +772,8 @@ void mtapi_network_plugin_finalize( ...@@ -468,9 +772,8 @@ void mtapi_network_plugin_finalize(
static void network_task_start( static void network_task_start(
MTAPI_IN mtapi_task_hndl_t task, MTAPI_IN mtapi_task_hndl_t task,
MTAPI_OUT mtapi_status_t* status) { MTAPI_OUT mtapi_status_t* status) {
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; // assume failure
int err; mtapi_status_set(status, MTAPI_ERR_UNKNOWN);
EMBB_UNUSED_IN_RELEASE(err);
if (embb_mtapi_node_is_initialized()) { if (embb_mtapi_node_is_initialized()) {
embb_mtapi_node_t * node = embb_mtapi_node_get_instance(); embb_mtapi_node_t * node = embb_mtapi_node_get_instance();
...@@ -491,69 +794,151 @@ static void network_task_start( ...@@ -491,69 +794,151 @@ static void network_task_start(
// serialize sending // serialize sending
embb_mutex_lock(&network_action->send_mutex); embb_mutex_lock(&network_action->send_mutex);
embb_mtapi_network_buffer_clear(send_buf);
// actual counts bytes actually put into the buffer
int actual = 0;
// expected counts bytes we intended to put into the buffer
int expected =
4 + // operation
4 + // domain_id
4 + // job_id
4 + // priority
4 + 4 + // task handle
4 + // result_size
4 + local_task->arguments_size; // arguments buffer
// packet size
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)expected);
expected += 4;
// operation is "start task" // operation is "start task"
err = embb_mtapi_network_buffer_push_back_int8( actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, EMBB_MTAPI_NETWORK_START_TASK); send_buf, EMBB_MTAPI_NETWORK_START_TASK);
assert(err == 1);
err = embb_mtapi_network_buffer_push_back_int32( // domain_id
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)network_action->domain_id); send_buf, (int32_t)network_action->domain_id);
assert(err == 4);
err = embb_mtapi_network_buffer_push_back_int32( // job_id
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)network_action->job_id); send_buf, (int32_t)network_action->job_id);
assert(err == 4);
err = embb_mtapi_network_buffer_push_back_int32( // priority
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)local_task->attributes.priority); send_buf, (int32_t)local_task->attributes.priority);
assert(err == 4);
err = embb_mtapi_network_buffer_push_back_int32( // task handle
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)local_task->handle.id); send_buf, (int32_t)local_task->handle.id);
assert(err == 4); actual += embb_mtapi_network_buffer_push_back_int32(
err = embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)local_task->handle.tag); send_buf, (int32_t)local_task->handle.tag);
assert(err == 4);
err = embb_mtapi_network_buffer_push_back_int32( // result size
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)local_task->result_size); send_buf, (int32_t)local_task->result_size);
assert(err == 4);
err = embb_mtapi_network_buffer_push_back_int32( // arguments buffer
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)local_task->arguments_size); send_buf, (int32_t)local_task->arguments_size);
assert(err == 4); actual += embb_mtapi_network_buffer_push_back_rawdata(
err = embb_mtapi_network_buffer_push_back_rawdata(
send_buf, (int32_t)local_task->arguments_size, local_task->arguments); send_buf, (int32_t)local_task->arguments_size, local_task->arguments);
assert(err == (int)local_task->arguments_size);
err = embb_mtapi_network_socket_sendbuffer( // check if everything fit into the buffer
&network_action->socket, send_buf); if (actual == expected) {
assert(err == send_buf->size); embb_atomic_fetch_and_add_int(&local_action->num_tasks, 1);
embb_atomic_store_int(&local_task->state, MTAPI_TASK_RUNNING);
embb_atomic_fetch_and_add_int(&local_action->num_tasks, 1); int sent = embb_mtapi_network_socket_sendbuffer(
embb_atomic_store_int(&local_task->state, MTAPI_TASK_RUNNING); &network_action->socket, send_buf);
// was everything sent?
if (sent == send_buf->size) {
// we've done it, success!
mtapi_status_set(status, MTAPI_SUCCESS);
} else {
// could not send the whole task, this will fail on the remote side,
// so we can safely assume that the task is in error
embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1);
embb_atomic_store_int(&local_task->state, MTAPI_TASK_ERROR);
}
}
embb_mtapi_network_buffer_clear(send_buf); embb_mtapi_network_buffer_clear(send_buf);
embb_mutex_unlock(&network_action->send_mutex); embb_mutex_unlock(&network_action->send_mutex);
local_status = MTAPI_SUCCESS;
} }
} }
} }
mtapi_status_set(status, local_status);
} }
static void network_task_cancel( static void network_task_cancel(
MTAPI_IN mtapi_task_hndl_t task, MTAPI_IN mtapi_task_hndl_t task,
MTAPI_OUT mtapi_status_t* status) { MTAPI_OUT mtapi_status_t* status) {
mtapi_status_t local_status = MTAPI_ERR_UNKNOWN; // assume failure
mtapi_status_set(status, MTAPI_ERR_UNKNOWN);
EMBB_UNUSED(task); if (embb_mtapi_node_is_initialized()) {
embb_mtapi_node_t * node = embb_mtapi_node_get_instance();
mtapi_status_set(status, local_status); if (embb_mtapi_task_pool_is_handle_valid(node->task_pool, task)) {
embb_mtapi_task_t * local_task =
embb_mtapi_task_pool_get_storage_for_handle(node->task_pool, task);
if (embb_mtapi_action_pool_is_handle_valid(
node->action_pool, local_task->action)) {
embb_mtapi_action_t * local_action =
embb_mtapi_action_pool_get_storage_for_handle(
node->action_pool, local_task->action);
embb_mtapi_network_action_t * network_action =
(embb_mtapi_network_action_t*)local_action->plugin_data;
embb_mtapi_network_buffer_t * send_buf = &network_action->send_buffer;
// serialize sending
embb_mutex_lock(&network_action->send_mutex);
embb_mtapi_network_buffer_clear(send_buf);
// actual counts bytes actually put into the buffer
int actual = 0;
// expected counts bytes we intended to put into the buffer
int expected =
4 + // operation
4 + 4; // task handle
// packet size
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)expected);
expected += 4;
// operation is "cancel task"
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, EMBB_MTAPI_NETWORK_CANCEL_TASK);
// task handle
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)local_task->handle.id);
actual += embb_mtapi_network_buffer_push_back_int32(
send_buf, (int32_t)local_task->handle.tag);
// check if everything fit into the buffer
if (actual == expected) {
int sent = embb_mtapi_network_socket_sendbuffer(
&network_action->socket, send_buf);
// was everything sent?
if (sent == send_buf->size) {
// we've done it, success!
mtapi_status_set(status, MTAPI_SUCCESS);
} else {
embb_atomic_store_int(&local_task->state, MTAPI_TASK_ERROR);
}
} else {
embb_atomic_store_int(&local_task->state, MTAPI_TASK_ERROR);
}
embb_mtapi_network_buffer_clear(send_buf);
embb_mutex_unlock(&network_action->send_mutex);
}
}
}
} }
static void network_action_finalize( static void network_action_finalize(
...@@ -602,34 +987,36 @@ mtapi_action_hndl_t mtapi_network_action_create( ...@@ -602,34 +987,36 @@ mtapi_action_hndl_t mtapi_network_action_create(
action->domain_id = domain_id; action->domain_id = domain_id;
action->job_id = remote_job_id; action->job_id = remote_job_id;
embb_mtapi_network_buffer_initialize( err = embb_mtapi_network_buffer_initialize(
&action->send_buffer, (int)plugin->buffer_size); &action->send_buffer, (int)plugin->buffer_size);
embb_mutex_init(&action->send_mutex, 0);
action->host = host;
action->port = port;
embb_mtapi_network_socket_initialize(&action->socket);
err = embb_mtapi_network_socket_connect(&action->socket, host, port);
if (0 != err) { if (0 != err) {
// store socket for select err = embb_mutex_init(&action->send_mutex, 0);
plugin->sockets[plugin->socket_count] = action->socket; if (EMBB_SUCCESS == err) {
plugin->socket_count++; action->host = host;
action->port = port;
action_hndl = mtapi_ext_plugin_action_create( embb_mtapi_network_socket_initialize(&action->socket);
local_job_id, err = embb_mtapi_network_socket_connect(&action->socket, host, port);
network_task_start, if (0 != err) {
network_task_cancel, // store socket for select
network_action_finalize, plugin->sockets[plugin->socket_count] = action->socket;
action, plugin->socket_count++;
NULL, 0, // no node local data obviously
MTAPI_NULL, action_hndl = mtapi_ext_plugin_action_create(
&local_status); local_job_id,
} else { network_task_start,
embb_mutex_destroy(&action->send_mutex); network_task_cancel,
embb_mtapi_network_buffer_finalize(&action->send_buffer); network_action_finalize,
embb_mtapi_network_socket_finalize(&action->socket); action,
embb_free(action); NULL, 0, // no node local data obviously
MTAPI_NULL,
&local_status);
} else {
embb_mutex_destroy(&action->send_mutex);
embb_mtapi_network_buffer_finalize(&action->send_buffer);
embb_mtapi_network_socket_finalize(&action->socket);
embb_free(action);
}
}
} }
} }
......
...@@ -28,9 +28,10 @@ ...@@ -28,9 +28,10 @@
#include <embb/base/c/memory_allocation.h> #include <embb/base/c/memory_allocation.h>
#include <string.h> #include <string.h>
void embb_mtapi_network_buffer_initialize( int embb_mtapi_network_buffer_initialize(
embb_mtapi_network_buffer_t * that, embb_mtapi_network_buffer_t * that,
int capacity) { int capacity) {
int result = 1;
that->position = 0; that->position = 0;
that->size = 0; that->size = 0;
that->data = (char*)embb_alloc((size_t)capacity); that->data = (char*)embb_alloc((size_t)capacity);
...@@ -38,7 +39,9 @@ void embb_mtapi_network_buffer_initialize( ...@@ -38,7 +39,9 @@ void embb_mtapi_network_buffer_initialize(
that->capacity = capacity; that->capacity = capacity;
} else { } else {
that->capacity = 0; that->capacity = 0;
result = 0;
} }
return result;
} }
void embb_mtapi_network_buffer_finalize( void embb_mtapi_network_buffer_finalize(
...@@ -107,6 +110,7 @@ int embb_mtapi_network_buffer_pop_front_int8( ...@@ -107,6 +110,7 @@ int embb_mtapi_network_buffer_pop_front_int8(
embb_mtapi_network_buffer_t * that, embb_mtapi_network_buffer_t * that,
int8_t * value) { int8_t * value) {
if (that->position + 1 > that->size) { if (that->position + 1 > that->size) {
*value = 0;
return 0; return 0;
} }
memcpy(value, that->data + that->position, 1); memcpy(value, that->data + that->position, 1);
...@@ -118,6 +122,7 @@ int embb_mtapi_network_buffer_pop_front_int16( ...@@ -118,6 +122,7 @@ int embb_mtapi_network_buffer_pop_front_int16(
embb_mtapi_network_buffer_t * that, embb_mtapi_network_buffer_t * that,
int16_t * value) { int16_t * value) {
if (that->position + 2 > that->size) { if (that->position + 2 > that->size) {
*value = 0;
return 0; return 0;
} }
memcpy(value, that->data + that->position, 2); memcpy(value, that->data + that->position, 2);
...@@ -129,6 +134,7 @@ int embb_mtapi_network_buffer_pop_front_int32( ...@@ -129,6 +134,7 @@ int embb_mtapi_network_buffer_pop_front_int32(
embb_mtapi_network_buffer_t * that, embb_mtapi_network_buffer_t * that,
int32_t * value) { int32_t * value) {
if (that->position + 4 > that->size) { if (that->position + 4 > that->size) {
*value = 0;
return 0; return 0;
} }
memcpy(value, that->data + that->position, 4); memcpy(value, that->data + that->position, 4);
...@@ -141,6 +147,7 @@ int embb_mtapi_network_buffer_pop_front_rawdata( ...@@ -141,6 +147,7 @@ int embb_mtapi_network_buffer_pop_front_rawdata(
int32_t size, int32_t size,
void * rawdata) { void * rawdata) {
if (that->position + size > that->size) { if (that->position + size > that->size) {
memset(rawdata, 0, (size_t)size);
return 0; return 0;
} }
memcpy(rawdata, that->data + that->position, (size_t)size); memcpy(rawdata, that->data + that->position, (size_t)size);
......
...@@ -43,7 +43,7 @@ struct embb_mtapi_network_buffer_struct { ...@@ -43,7 +43,7 @@ struct embb_mtapi_network_buffer_struct {
typedef struct embb_mtapi_network_buffer_struct embb_mtapi_network_buffer_t; typedef struct embb_mtapi_network_buffer_struct embb_mtapi_network_buffer_t;
void embb_mtapi_network_buffer_initialize( int embb_mtapi_network_buffer_initialize(
embb_mtapi_network_buffer_t * that, embb_mtapi_network_buffer_t * that,
int capacity int capacity
); );
......
...@@ -71,13 +71,6 @@ int embb_mtapi_network_socket_bind_and_listen( ...@@ -71,13 +71,6 @@ int embb_mtapi_network_socket_bind_and_listen(
uint16_t port, uint16_t port,
uint16_t max_connections) { uint16_t max_connections) {
struct sockaddr_in in_addr; struct sockaddr_in in_addr;
int reuseaddr_on = 1;
// addr reuse
if (SOCKET_ERROR == setsockopt(that->handle, SOL_SOCKET, SO_REUSEADDR,
(const char *)&reuseaddr_on, sizeof(reuseaddr_on))) {
return 0;
}
// bind & listen // bind & listen
memset(&in_addr, 0, sizeof(in_addr)); memset(&in_addr, 0, sizeof(in_addr));
...@@ -123,7 +116,8 @@ int embb_mtapi_network_socket_connect( ...@@ -123,7 +116,8 @@ int embb_mtapi_network_socket_connect(
if (SOCKET_ERROR == connect(that->handle, (struct sockaddr *)&addr, if (SOCKET_ERROR == connect(that->handle, (struct sockaddr *)&addr,
sizeof(addr))) { sizeof(addr))) {
#ifdef _WIN32 #ifdef _WIN32
if (WSAEWOULDBLOCK != WSAGetLastError()) int err = WSAGetLastError();
if (WSAEWOULDBLOCK != err)
#else #else
if (EAGAIN != errno) if (EAGAIN != errno)
#endif #endif
......
...@@ -61,13 +61,52 @@ static void test( ...@@ -61,13 +61,52 @@ static void test(
} }
} }
static void cancel_test(
void const * /*arguments*/,
mtapi_size_t /*arguments_size*/,
void * /*result_buffer*/,
mtapi_size_t /*result_buffer_size*/,
void const * /*node_local_data*/,
mtapi_size_t /*node_local_data_size*/,
mtapi_task_context_t * context) {
mtapi_status_t status;
while (true) {
mtapi_task_state_t state = mtapi_context_taskstate_get(context, &status);
if (status != MTAPI_SUCCESS) {
break;
} else {
if (state == MTAPI_TASK_CANCELLED) {
break;
}
}
}
}
NetworkTaskTest::NetworkTaskTest() { NetworkTaskTest::NetworkTaskTest() {
CreateUnit("mtapi network task test").Add(&NetworkTaskTest::TestBasic, this); CreateUnit("mtapi network task test")
.Add(&NetworkTaskTest::TestBasic, this);
} }
void NetworkTaskTest::TestBasic() { void NetworkTaskTest::TestBasic() {
mtapi_status_t status; mtapi_status_t status;
mtapi_initialize(
NETWORK_DOMAIN,
NETWORK_LOCAL_NODE,
MTAPI_NULL,
MTAPI_NULL,
&status);
MTAPI_CHECK_STATUS(status);
TestSimple();
TestCancel();
mtapi_finalize(&status);
MTAPI_CHECK_STATUS(status);
}
void NetworkTaskTest::TestSimple() {
mtapi_status_t status;
mtapi_job_hndl_t job; mtapi_job_hndl_t job;
mtapi_task_hndl_t task; mtapi_task_hndl_t task;
mtapi_action_hndl_t network_action, local_action; mtapi_action_hndl_t network_action, local_action;
...@@ -81,14 +120,6 @@ void NetworkTaskTest::TestBasic() { ...@@ -81,14 +120,6 @@ void NetworkTaskTest::TestBasic() {
arguments[ii + kElements] = static_cast<float>(ii); arguments[ii + kElements] = static_cast<float>(ii);
} }
mtapi_initialize(
NETWORK_DOMAIN,
NETWORK_LOCAL_NODE,
MTAPI_NULL,
MTAPI_NULL,
&status);
MTAPI_CHECK_STATUS(status);
mtapi_network_plugin_initialize("127.0.0.1", 12345, 5, mtapi_network_plugin_initialize("127.0.0.1", 12345, 5,
kElements * 4 * 3 + 32, &status); kElements * 4 * 3 + 32, &status);
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
...@@ -139,7 +170,68 @@ void NetworkTaskTest::TestBasic() { ...@@ -139,7 +170,68 @@ void NetworkTaskTest::TestBasic() {
mtapi_network_plugin_finalize(&status); mtapi_network_plugin_finalize(&status);
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
}
mtapi_finalize(&status); void NetworkTaskTest::TestCancel() {
mtapi_status_t status;
mtapi_job_hndl_t job;
mtapi_task_hndl_t task;
mtapi_action_hndl_t network_action, local_action;
float argument = 1.0f;
float result;
mtapi_network_plugin_initialize("127.0.0.1", 12346, 5,
4 * 3 + 32, &status);
MTAPI_CHECK_STATUS(status);
float node_remote = 1.0f;
local_action = mtapi_action_create(
NETWORK_REMOTE_JOB,
cancel_test,
&node_remote, sizeof(float),
MTAPI_DEFAULT_ACTION_ATTRIBUTES,
&status);
MTAPI_CHECK_STATUS(status);
network_action = mtapi_network_action_create(
NETWORK_DOMAIN,
NETWORK_LOCAL_JOB,
NETWORK_REMOTE_JOB,
"127.0.0.1", 12346,
&status);
MTAPI_CHECK_STATUS(status);
status = MTAPI_ERR_UNKNOWN;
job = mtapi_job_get(NETWORK_LOCAL_JOB, NETWORK_DOMAIN, &status);
MTAPI_CHECK_STATUS(status);
task = mtapi_task_start(
MTAPI_TASK_ID_NONE,
job,
&argument, sizeof(float),
&result, sizeof(float),
MTAPI_DEFAULT_TASK_ATTRIBUTES,
MTAPI_GROUP_NONE,
&status);
MTAPI_CHECK_STATUS(status);
mtapi_task_wait(task, 1, &status);
PT_ASSERT_EQ(status, MTAPI_TIMEOUT);
mtapi_task_cancel(task, &status);
MTAPI_CHECK_STATUS(status);
mtapi_task_wait(task, MTAPI_INFINITE, &status);
PT_ASSERT_NE(status, MTAPI_TIMEOUT);
PT_ASSERT_EQ(status, MTAPI_ERR_ACTION_CANCELLED);
mtapi_action_delete(network_action, MTAPI_INFINITE, &status);
MTAPI_CHECK_STATUS(status);
mtapi_action_delete(local_action, MTAPI_INFINITE, &status);
MTAPI_CHECK_STATUS(status);
mtapi_network_plugin_finalize(&status);
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
} }
...@@ -35,6 +35,9 @@ class NetworkTaskTest : public partest::TestCase { ...@@ -35,6 +35,9 @@ class NetworkTaskTest : public partest::TestCase {
private: private:
void TestBasic(); void TestBasic();
void TestSimple();
void TestCancel();
}; };
#endif // MTAPI_PLUGINS_C_MTAPI_NETWORK_C_TEST_EMBB_MTAPI_NETWORK_TEST_TASK_H_ #endif // MTAPI_PLUGINS_C_MTAPI_NETWORK_C_TEST_EMBB_MTAPI_NETWORK_TEST_TASK_H_
...@@ -130,6 +130,24 @@ class Node { ...@@ -130,6 +130,24 @@ class Node {
} }
/** /**
* Returns the number of available groups.
* \return The number of available groups
* \waitfree
*/
mtapi_uint_t GetGroupCount() const {
return group_count_;
}
/**
* Returns the number of available tasks.
* \return The number of available tasks
* \waitfree
*/
mtapi_uint_t GetTaskLimit() const {
return task_limit_;
}
/**
* Returns the number of available cores. * Returns the number of available cores.
* \return The number of available cores * \return The number of available cores
* \waitfree * \waitfree
...@@ -229,6 +247,8 @@ class Node { ...@@ -229,6 +247,8 @@ class Node {
mtapi_task_context_t * context); mtapi_task_context_t * context);
mtapi_uint_t queue_count_; mtapi_uint_t queue_count_;
mtapi_uint_t group_count_;
mtapi_uint_t task_limit_;
mtapi_uint_t core_count_; mtapi_uint_t core_count_;
mtapi_uint_t worker_thread_count_; mtapi_uint_t worker_thread_count_;
mtapi_action_hndl_t action_handle_; mtapi_action_hndl_t action_handle_;
......
...@@ -41,7 +41,7 @@ namespace { ...@@ -41,7 +41,7 @@ namespace {
static embb::tasks::Node * node_instance = NULL; static embb::tasks::Node * node_instance = NULL;
#if TASKS_CPP_AUTOMATIC_INITIALIZE #if TASKS_CPP_AUTOMATIC_INITIALIZE
static embb::base::Mutex init_mutex; static embb_spinlock_t init_mutex = { { 0 } };
#endif #endif
} }
...@@ -78,6 +78,12 @@ Node::Node( ...@@ -78,6 +78,12 @@ Node::Node(
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_QUEUES, &queue_count_, mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_QUEUES, &queue_count_,
sizeof(queue_count_), &status); sizeof(queue_count_), &status);
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_GROUPS, &group_count_,
sizeof(group_count_), &status);
assert(MTAPI_SUCCESS == status);
mtapi_node_get_attribute(node_id, MTAPI_NODE_MAX_TASKS, &task_limit_,
sizeof(queue_count_), &status);
assert(MTAPI_SUCCESS == status);
core_count_ = info.hardware_concurrency; core_count_ = info.hardware_concurrency;
worker_thread_count_ = embb_core_set_count(&attr->core_affinity); worker_thread_count_ = embb_core_set_count(&attr->core_affinity);
action_handle_ = mtapi_action_create(TASKS_CPP_JOB, action_func, action_handle_ = mtapi_action_create(TASKS_CPP_JOB, action_func,
...@@ -126,7 +132,7 @@ void Node::Initialize( ...@@ -126,7 +132,7 @@ void Node::Initialize(
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS, mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS,
&tmp, sizeof(tmp), &status); &tmp, sizeof(tmp), &status);
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
tmp = 4; // tmp = 4;
mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_JOBS, mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_JOBS,
&tmp, sizeof(tmp), &status); &tmp, sizeof(tmp), &status);
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
...@@ -207,13 +213,13 @@ bool Node::IsInitialized() { ...@@ -207,13 +213,13 @@ bool Node::IsInitialized() {
Node & Node::GetInstance() { Node & Node::GetInstance() {
#if TASKS_CPP_AUTOMATIC_INITIALIZE #if TASKS_CPP_AUTOMATIC_INITIALIZE
if (!IsInitialized()) { if (!IsInitialized()) {
init_mutex.Lock(); embb_spin_lock(&init_mutex);
if (!IsInitialized()) { if (!IsInitialized()) {
Node::Initialize( Node::Initialize(
TASKS_CPP_AUTOMATIC_DOMAIN_ID, TASKS_CPP_AUTOMATIC_NODE_ID); TASKS_CPP_AUTOMATIC_DOMAIN_ID, TASKS_CPP_AUTOMATIC_NODE_ID);
atexit(Node::Finalize); atexit(Node::Finalize);
} }
init_mutex.Unlock(); embb_spin_unlock(&init_mutex);
} }
return *node_instance; return *node_instance;
#else #else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment