eclipse-threadx / threadx

Eclipse ThreadX is an advanced real-time operating system (RTOS) designed specifically for deeply embedded applications.
https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/threadx/index.md
MIT License
2.87k stars 782 forks source link

Allow passing of custom context to tx_*_notify #212

Closed alobop closed 1 year ago

alobop commented 1 year ago

I’m working with threadx and I wanted to use the event chaining for one of my applications. I noticed that it is not possible to pass down a private context for the callback (unlike other functions that allow arbitrary user context such as the thread_create, timer_create). Since this is not possible, it forces the callee to have a static context for modules that use the event chaining feature.


struct DRIVER_X
{
    TX_THREAD WorkingThread;
    TX_SEMAPHORE ThreadWakeup;

    TX_EVENT_FLAGS_GROUP InterruptStatus;
    TX_QUEUE UserRequests;
};

DRIVER_X instanceA;
DRIVER_X instanceB;

InitDriverX(&instanceA);
InitDriverX(&instanceB);

....

void InitDriverX(DRIVER_X* driver)
{
    tx_thread_create(driver->WorkingThread, "WorkingThread", driver, ....);
    tx_semaphore_create(driver->ThreadWakeup, "Wakeup", 0);
    tx_event_flags_create(driver->InterruptStatus, "Status");
    tx_queue_create(driver->UserRequests, "Reqs", ...);

    /* Chain flag and queue into the semaphore */
    tx_queue_send_notify(..., QueueNotify);
    tx_event_flag_set_notify(..., FlagNotify);
}

static void QueueNotify(TX_QUEUE* pQueue)
{
    // How to differentiate between a call for instanceA vs instanceB?
    tx_semaphore_put(??????);
} 

static void FlagNotify(TX_EVENT_FLAGS_GROUP* pQueue)
{
    // How to differentiate between a call for instanceA vs instanceB?
    tx_semaphore_put(??????);
}

vs

struct DRIVER_X
{
    TX_THREAD WorkingThread;
    TX_SEMAPHORE ThreadWakeup;

    TX_EVENT_FLAGS_GROUP InterruptStatus;
    TX_QUEUE UserRequests;
};

DRIVER_X instanceA;
DRIVER_X instanceB;

InitDriverX(&instanceA);
InitDriverX(&instanceB);

....

void InitDriverX(DRIVER_X* driver)
{
    tx_thread_create(driver->WorkingThread, "WorkingThread", driver, ....);
    tx_semaphore_create(driver->ThreadWakeup, "Wakeup", 0);
    tx_event_flags_create(driver->InterruptStatus, "Status");
    tx_queue_create(driver->UserRequests, "Reqs", ...);

    /* Chain flag and queue into the semaphore */
    tx_queue_send_notify(..., QueueNotify, driver);
    tx_event_flag_set_notify(..., FlagNotify, driver);
}

static void QueueNotify(TX_QUEUE* pQueue, void* pContext)
{
    DRIVER_X* pDriver = pContext;
    tx_semaphore_put(pDriver->ThreadWakeup);
} 

static void FlagNotify(TX_EVENT_FLAGS_GROUP* pQueue, void* pContext)
{
    DRIVER_X* pDriver = pContext;
    tx_semaphore_put(pDriver->ThreadWakeup);
}
goldscott commented 1 year ago

Yeah, you're right, there's no good way to pass custom context.

One possibility is to use the extension members of the structs to store custom context, e.g. you can define the TX_QUEUE_EXTENSION member of the queue struct: https://github.com/azure-rtos/threadx/blob/master/common/inc/tx_api.h#L939

goldscott commented 1 year ago

Closing. Anyone feel free to re-open if there are further questions related to this.