Skip to content

Commit

Permalink
Changed Wait and Notify to be able to use custom SubTypes of notifica…
Browse files Browse the repository at this point in the history
…tion, allowing custom notifications to be created by developers
  • Loading branch information
solariun committed Jan 22, 2022
1 parent edb70b7 commit 4e5b8d6
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 83 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# AtomicX

Version 1.1.0 release
Version 1.1.3 release

![image](https://user-images.githubusercontent.com/1805792/125191254-6591cf80-e239-11eb-9e89-d7500e793cd4.png)

What is AtomicX? AtomicX is a general purpose **cooperative** thread lib for embedded applications (single core or confined within other RTOS) that allows you partition your application "context" (since core execution) into several controlled context using cooperative thread. So far here nothing out of the ordinary, right? Lets think again:

# Backlog and updates

## Version 1.1.3

* Added a Thermal Camera Demo ported from CorePartition but now fully object oriented

* **POWERFUL**: Now `Wait`\`Notify` will accept a new parameter called subType, the name gives no clue but it is really powerfull it allows developer to create custom Types of notifications, that same stratage is used to when you use syncNotify that will block anting timeout occur or a wait is issue.

## Version 1.1.2

* **Important* `Notify` was split into `Notify` and `SyncNotify` to avoid compilation ambiguity reported for some boards, all the examples have been migrated to use one of those accordingly and tested against all supported processors.
Expand Down
188 changes: 107 additions & 81 deletions atomicx/atomicx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include <setjmp.h>

/* Official version */
#define ATOMICX_VERSION "1.1.2"
#define ATOMICX_VERSION "1.1.3"
#define ATOMIC_VERSION_LABEL "AtomicX v" ATOMICX_VERSION " built at " __TIMESTAMP__

using atomicx_time = uint32_t;
Expand Down Expand Up @@ -802,52 +802,20 @@ namespace thread
return;
}

protected:

struct Message
{
size_t tag;
size_t message;
};

/**
* @brief calculate the Topic ID for a given topic text
*
* @param pszTopic Topic Text in C string
* @param nKeyLenght Size, in bytes + zero terminated char
*
* @return uint32_t The calculated topic ID
*/
uint32_t GetTopicID (const char* pszTopic, size_t nKeyLenght);

/**
* ------------------------------
* SMART WAIT/NOTIFY IMPLEMENTATION
* ------------------------------
* SPECIAL PRIVATE SECTION FOR HELPER METHODS USED BY PROCTED METHODS
*/
private:

/**
* @brief Check if there are waiting threads for a given reference pointer and tag value
*
* @tparam T Type of the reference pointer
* @param refVar The reference pointer used a a notifier
* @param nTag The size_t tag that will give meaning to the notification, if nTag == 0 mean all bTag for the refVar
*
* @return true
*
* @note This is a powerful tool since it create layers of waiting within the same reference pointer
*/
template<typename T> bool IsWaiting(T& refVar, size_t nTag=0)
template<typename T> void SetWaitParammeters (T& refVar, size_t nTag=0, aSubTypes asubType = aSubTypes::wait)
{
for (auto& thr : *this)
{
if (thr.m_aStatus == aTypes::wait && thr.m_pLockId == (void*) &refVar && (nTag == 0 || thr.m_lockMessage.tag == nTag))
{
return true;
}
}
m_TopicId = 0;
m_pLockId = (uint8_t*)&refVar;
m_aStatus = aTypes::wait;
m_aSubStatus = asubType;

return false;
m_lockMessage.tag = nTag;
m_lockMessage.message = 0;
}

/**
Expand Down Expand Up @@ -890,6 +858,49 @@ namespace thread
return nRet;
}

/**
* @brief Safely notify all LookForWaitings from a specific reference pointer along with a message without triggering context change
*
* @tparam T Type of the reference pointer
* @param refVar The reference pointer used a a notifier
* @param nTag The size_t tag that will give meaning to the notification, if nTag == 0 means wait all refVar regardless
*
* @return true if at least one got notified, otherwise false.
*/
template<typename T> size_t SafeNotifyLookWaitings(T& refVar, size_t nTag)
{
size_t message=0;

return SafeNotifier(message, refVar, nTag, aSubTypes::look);
}

/**
* PROTECTED METHODS, THOSE WILL BE ONLY ACCESSIBLE BY THE THREAD ITSELF
*/
protected:

struct Message
{
size_t tag;
size_t message;
};

/**
* @brief calculate the Topic ID for a given topic text
*
* @param pszTopic Topic Text in C string
* @param nKeyLenght Size, in bytes + zero terminated char
*
* @return uint32_t The calculated topic ID
*/
uint32_t GetTopicID (const char* pszTopic, size_t nKeyLenght);

/**
* ------------------------------
* SMART WAIT/NOTIFY IMPLEMENTATION
* ------------------------------
*/

/**
* @brief Sync with thread call for a wait (refVar,nTag)
*
Expand All @@ -904,12 +915,7 @@ namespace thread
{
if (IsWaiting(refVar, nTag) == false)
{
m_TopicId = 0;
m_pLockId = (uint8_t*)&refVar;
m_aStatus = aTypes::wait;
m_aSubStatus = aSubTypes::look;

m_lockMessage.tag = nTag;
SetWaitParammeters (refVar, nTag, aSubTypes::look);

Yield(waitFor);

Expand All @@ -925,19 +931,27 @@ namespace thread
}

/**
* @brief Safely notify all LookForWaitings from a specific reference pointer along with a message without triggering context change
* @brief Check if there are waiting threads for a given reference pointer and tag value
*
* @tparam T Type of the reference pointer
* @param refVar The reference pointer used a a notifier
* @param nTag The size_t tag that will give meaning to the notification, if nTag == 0 means wait all refVar regardless
* @param nTag The size_t tag that will give meaning to the notification, if nTag == 0 mean all bTag for the refVar
*
* @return true if at least one got notified, otherwise false.
* @return true
*
* @note This is a powerful tool since it create layers of waiting within the same reference pointer
*/
template<typename T> size_t SafeNotifyLookWaitings(T& refVar, size_t nTag)
template<typename T> bool IsWaiting(T& refVar, size_t nTag=0)
{
size_t message=0;
for (auto& thr : *this)
{
if (thr.m_aStatus == aTypes::wait && thr.m_pLockId == (void*) &refVar && (nTag == 0 || thr.m_lockMessage.tag == nTag))
{
return true;
}
}

return SafeNotifier(message, refVar, nTag, aSubTypes::look);
return false;
}

/**
Expand All @@ -947,17 +961,16 @@ namespace thread
* @param nMessage the size_t message to be received
* @param refVar the reference pointer used as a notifier
* @param nTag the size_t tag that will give meaning to the the message, if nTag == 0 means wait all refVar regardless
*
* @param waitFor default==0 (undefinitly), How log to wait for a notification based on atomicx_time
* @param asubType Type of the notification, only use it if you know what you are doing, it creates a different
* type of wait/notify, deafault == aSubType::wait
* @return true if it was successfully received.
*/
template<typename T> bool Wait(size_t& nMessage, T& refVar, size_t nTag=0, atomicx_time waitFor=0)
template<typename T> bool Wait(size_t& nMessage, T& refVar, size_t nTag=0, atomicx_time waitFor=0, aSubTypes asubType = aSubTypes::wait)
{
SafeNotifyLookWaitings(refVar, nTag);

m_TopicId = 0;
m_pLockId = (uint8_t*)&refVar;
m_aStatus = aTypes::wait;
m_aSubStatus = aSubTypes::wait;
SetWaitParammeters (refVar, nTag, aSubTypes::wait);

m_lockMessage.tag = nTag;

Expand All @@ -984,17 +997,17 @@ namespace thread
* @tparam T Type of the reference pointer
* @param refVar the reference pointer used as a notifier
* @param nTag the size_t tag that will give meaning to the the message, if nTag == 0 means wait all refVar regardless
* @param waitFor default==0 (undefinitly), How log to wait for a notification based on atomicx_time
* @param asubType Type of the notification, only use it if you know what you are doing, it creates a different
* type of wait/notify, deafault == aSubType::wait
*
* @return true if it was successfully received.
*/
template<typename T> bool Wait(T& refVar, size_t nTag=0, atomicx_time waitFor=0)
template<typename T> bool Wait(T& refVar, size_t nTag=0, atomicx_time waitFor=0, aSubTypes asubType = aSubTypes::wait)
{
SafeNotifyLookWaitings(refVar, nTag);

m_TopicId = 0;
m_pLockId = (uint8_t*)&refVar;
m_aStatus = aTypes::wait;
m_aSubStatus = aSubTypes::wait;
SetWaitParammeters (refVar, nTag, aSubTypes::wait);

m_lockMessage.tag = nTag;

Expand Down Expand Up @@ -1022,12 +1035,14 @@ namespace thread
* @param nTag The size_t tag that will give meaning to the notification, if nTag == 0 means notify all refVar regardless
* @param bAll default = false, and only the fist available refVar Waiting thread will be notified, if true all available
* refVar waiting thread will be notified.
* @param asubType Type of the notification, only use it if you know what you are doing, it creates a different
* type of wait/notify, deafault == aSubType::wait
*
* @return true if at least one got notified, otherwise false.
*/
template<typename T> size_t SafeNotify(size_t& nMessage, T& refVar, size_t nTag=0, bool bAll=false)
template<typename T> size_t SafeNotify(size_t& nMessage, T& refVar, size_t nTag=0, bool bAll=false, aSubTypes asubType = aSubTypes::wait)
{
return SafeNotifier(nMessage, refVar, nTag, aSubTypes::wait, bAll);
return SafeNotifier(nMessage, refVar, nTag, asubType, bAll);
}

/**
Expand All @@ -1039,21 +1054,23 @@ namespace thread
* @param nTag The size_t tag that will give meaning to the notification, if nTag == 0 means notify all refVar regardless
* @param bAll default = false, and only the fist available refVar Waiting thread will be notified, if true all available
* refVar waiting thread will be notified.
* @param asubType Type of the notification, only use it if you know what you are doing, it creates a different
* type of wait/notify, deafault == aSubType::wait
*
* @return true if at least one got notified, otherwise false.
*/
template<typename T> size_t Notify(size_t& nMessage, T& refVar, size_t nTag=0, bool bAll=false)
template<typename T> size_t Notify(size_t& nMessage, T& refVar, size_t nTag=0, bool bAll=false, aSubTypes asubType = aSubTypes::wait)
{
size_t bRet = SafeNotify (nMessage, refVar, nTag, bAll);
size_t bRet = SafeNotify (nMessage, refVar, nTag, bAll, asubType);

if (bRet) Yield(0);

return bRet;
}

template<typename T> size_t Notify(size_t&& nMessage, T& refVar, size_t nTag=0, bool bAll=false)
template<typename T> size_t Notify(size_t&& nMessage, T& refVar, size_t nTag=0, bool bAll=false, aSubTypes asubType = aSubTypes::wait)
{
size_t bRet = SafeNotify (nMessage, refVar, nTag, bAll);
size_t bRet = SafeNotify (nMessage, refVar, nTag, bAll, asubType);

if (bRet) Yield(0);

Expand All @@ -1070,31 +1087,33 @@ namespace thread
* @param waitForWaitings default=0 (waiting for Waiting calls) othersize wait for Wait commands compatible with the paramenters (Sync call).
* @param bAll default = false, and only the fist available refVar Waiting thread will be notified, if true all available
* refVar waiting thread will be notified.
* @param asubType Type of the notification, only use it if you know what you are doing, it creates a different
* type of wait/notify, deafault == aSubType::wait
*
* @return true if at least one got notified, otherwise false.
*/
template<typename T> size_t SyncNotify(size_t& nMessage, T& refVar, size_t nTag=0, atomicx_time waitForWaitings=0, bool bAll=false)
template<typename T> size_t SyncNotify(size_t& nMessage, T& refVar, size_t nTag=0, atomicx_time waitForWaitings=0, bool bAll=false, aSubTypes asubType = aSubTypes::wait)
{
if (LookForWaitings (refVar, nTag, waitForWaitings) == false)
{
return 0;
}

size_t bRet = SafeNotify (nMessage, refVar, nTag, bAll);
size_t bRet = SafeNotify (nMessage, refVar, nTag, bAll, asubType);

if (bRet) Yield(0);

return bRet;
}

template<typename T> size_t SyncNotify(size_t&& nMessage, T& refVar, size_t nTag=0, atomicx_time waitForWaitings=0, bool bAll=false)
template<typename T> size_t SyncNotify(size_t&& nMessage, T& refVar, size_t nTag=0, atomicx_time waitForWaitings=0, bool bAll=false, aSubTypes asubType = aSubTypes::wait)
{
if (LookForWaitings (refVar, nTag, waitForWaitings) == false)
{
return 0;
}

size_t bRet = SafeNotify (nMessage, refVar, nTag, bAll);
size_t bRet = SafeNotify (nMessage, refVar, nTag, bAll, asubType);

if (bRet) Yield(0);

Expand All @@ -1109,13 +1128,15 @@ namespace thread
* @param nTag The size_t tag that will give meaning to the notification, if nTag == 0 means notify all refVar regardless
* @param bAll default = false, and only the fist available refVar Waiting thread will be notified, if true all available
* refVar waiting thread will be notified.
* @param asubType Type of the notification, only use it if you know what you are doing, it creates a different
* type of wait/notify, deafault == aSubType::wait
*
* @return true if at least one got notified, otherwise false.
*/
template<typename T> size_t SafeNotify(T& refVar, size_t nTag=0, bool bAll=false)
template<typename T> size_t SafeNotify(T& refVar, size_t nTag=0, bool bAll=false, aSubTypes asubType = aSubTypes::wait)
{
size_t message=0;
return SafeNotifier (message, refVar, nTag, aSubTypes::wait, bAll);
return SafeNotifier (message, refVar, nTag, asubType, bAll);
}

/**
Expand All @@ -1127,17 +1148,19 @@ namespace thread
* @param waitForWaitings default=0 (waiting for Waiting calls) othersize wait for Wait commands compatible with the paramenters (Sync call).
* @param bAll default = false, and only the fist available refVar Waiting thread will be notified, if true all available
* refVar waiting thread will be notified.
* @param asubType Type of the notification, only use it if you know what you are doing, it creates a different
* type of wait/notify, deafault == aSubType::wait
*
* @return true if at least one got notified, otherwise false.
*/
template<typename T> size_t SyncNotify(T& refVar, size_t nTag, atomicx_time waitForWaitings=0, bool bAll=false)
template<typename T> size_t SyncNotify(T& refVar, size_t nTag, atomicx_time waitForWaitings=0, bool bAll=false, aSubTypes asubType = aSubTypes::wait)
{
if (LookForWaitings (refVar, nTag, waitForWaitings) == false)
{
return 0;
}

size_t bRet = SafeNotify(refVar, nTag, bAll);
size_t bRet = SafeNotify(refVar, nTag, bAll, asubType);

if (bRet) Yield(0);

Expand All @@ -1152,11 +1175,14 @@ namespace thread
* @param nTag The size_t tag that will give meaning to the notification, if nTag == 0 means notify all refVar regardless
* @param bAll default = false, and only the fist available refVar Waiting thread will be notified, if true all available
* refVar waiting thread will be notified.
* @param asubType Type of the notification, only use it if you know what you are doing, it creates a different
* type of wait/notify, deafault == aSubType::wait
*
* @return true if at least one got notified, otherwise false.
*/
template<typename T> size_t Notify(T& refVar, size_t nTag=0, bool bAll=false)
template<typename T> size_t Notify(T& refVar, size_t nTag=0, bool bAll=false, aSubTypes asubType = aSubTypes::wait)
{
size_t bRet = SafeNotify(refVar, nTag, bAll);
size_t bRet = SafeNotify(refVar, nTag, bAll, asubType);

if (bRet) Yield(0);

Expand Down
Loading

0 comments on commit 4e5b8d6

Please sign in to comment.