Bidirectional Spontaneous Event Design Pattern

Technical questions regarding the xTIMEcomposer, xSOFTip Explorer and Programming with XMOS.
Posts: 9
Joined: Thu Oct 06, 2016 4:58 am

Bidirectional Spontaneous Event Design Pattern

Postby gcore » Thu May 18, 2017 7:40 am

Hi all,

I'm trying to design a Bidirectional Spontaneous Event Design Pattern where the main application would create an array of channels, pass all of them to one task that would be the Message Master, and the other end of each channel to a respective Task. The tasks would each identify themselves with the Message Master, and then would all be able to do whatever job they needed, and send events to each other ad hoc via the Message Master task. This would avoid the need to sacrifice chanends for connections between any two arbitrary tasks, but at the expense of highly determinate low latency communication which is a trade-off I'm happy to live with.

Pretty much what is mentioned at this link:

I've tried a number of iterations of implementing this, including using module_mutual_thread_comm from the sc_util library mentioned on that page, but still haven't found a solution that properly gets the job done. I've satisfied myself that module_mutual_thread_comm can be used between two tasks, each hammering the other with no data loss or deadlock. I'm yet to have the same success if I add a third task, with one task dedicated to being the Message Master allowing the other two tasks to communicate with each other via it.

This sort of design pattern is something that I've used in a number of other firmware development tasks on other platforms. For example, multiple threads on a Linux system, all able to send events to each other. I'm hoping to implement at least a rudimentary but robust messaging scheme on XMOS.

Could anyone recommend an approach, or an existing library for achieving this design pattern between N tasks on different cores and tiles on an xCORE-200 device?
User avatar
Experienced Member
Posts: 113
Joined: Fri Dec 11, 2009 10:22 am

Postby andrew » Fri Jun 23, 2017 8:32 am

Sorry I don't think I fully understand the problem. Correct me if I'm wrong: There is one Message Master dishing out jobs to slaves. The slave accepts a job does it then lets the Message Master know so another can be assigned to it. Is that correct?
Posts: 9
Joined: Thu Oct 06, 2016 4:58 am

Postby gcore » Mon Jun 26, 2017 12:47 am

In this pattern there is one messaging master task and multiple worker tasks. The messaging master exists only to act as a "post office", with the rest of the work being perfomed in the worker tasks. This allows worker tasks to communicate ad-hoc with each other without requiring separate channel connections between each other. Messages come in from worker tasks with a destination worker task specified, and get routed through to that destination worker task.

The main reason for wanting this is to allow many worker tasks to communicate with each other, each consuming only one channel connection no matter how many tasks they each need to communicate with.

I have now successfully implemented this using module_mutual_thread_comm and module_xfifo from sc_util. In my implementation the "messaging master" holds a collection of module_mutual_thread_comm "NotifyingSlave" nodes, one for each worker task, and also one xfifo for each worker task, for buffering messages destined for that task. The worker tasks each act as a "ReactiveMaster". Note the master/slave terminology is reversed when considering individual mutual_thread_comm connections versus the worker (slave) tasks and the messaging master.

The messaging master is implemented to be mostly idle, able to execute a select case responsively. The sending of a message from a worker to the master is a blocking operation, but can be expected to unblock quickly. While this initial transaction between the sender and the master is synchronous, the overall message passing process to the destination task should be considered to be asynchronous. Once the master has buffered the message in a fifo associated with the destination, it will notify the destination task, which will read the message when its ready. Like the initial write, this read operation is itself synchronous.

  • Any worker task can send any other worker task a message. It goes via the messaging master.
  • Any worker task can send itself a message. It goes via the master.

I won't be able to provide code, but that's the general gist.

Who is online

Users browsing this forum: No registered users and 19 guests