Using Channels to effect asynchronous threads

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Using Channels to effect asynchronous threads

Post by Obtuse »

I am trying to use a single channel on XS1-L2 to operate threads on separate cores in a asynchronous manner.

The plan: Single Channel.

core [1] open channel for rx and block. chan :> rx; (waiting)
core [0] do something? send tx on channel. chan <: tx;
core [0] wait for channel input(block). chan :> rx;(waiting)
core [1] rx data, then send close channel. chan :> rx; chan <: TX close;
core [0] receive close channel, do something. chan :> ACK close;
loop to top.

Questions:

1) How to close a channel?

I have read about END and EOM but have no idea how to set this up or use it.

2) Is this type of material available in the printed book?

I have seen XS1_CT_END on-line. What is that, and where is info?

Thanks for any help.

Len


User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

Post by rp181 »

Disclaimer: I don't have much experience with the instruction set and low level assembly programming.

As far as I understand it, channels don't actually stay open. When you declare a channel, nothing is done until you actually use it. When you send something through the channel, the channel is opened, data is sent, and the channel is closed, automatically. This is why you can have many, many channels, even though the switch can only handle 4 open connections (between cores). You don't have to manually close the channel.

Streaming channels, on the other hand, remain open, and therefor, provides a much higher data throughput.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Using chan (not streaming chan)

will make the

chan :> rx;

translate into 5 instructions. On the sending (master) side it will look like this.

"Open channel"
Send Control token from master thread to slave thread
Wait for and check controltoken sent from the slave
Send data
"Close channel"
Send Control token from master thread to slave thread
Wait for and check controltoken sent from the slave

If you want to send more data Before the channel is shut down, you can use a transaction with
master{} / slave{} in XC.
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Post by Obtuse »

rp181,

Does not work. At least here.

As long as the channel is open it will block one thread when no data is flowing in or out.
In other words a thread will bind up unless both ends of a channel are able to move data. This is the property of channels I wish to take advantage of. However, in order to circumvent this in some circumstances the channel would have to be shut down so no thread blocking would occur on either end.

Think of it as monitoring a 1 pin port on one core connected to another port on the other core. I'm just trying to do it using a channel and no wires.

I see it mentioned in other threads, but have no knowledge as to how to do it.

If it can't be done I'll look for some other solution.
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Post by Obtuse »

lilltroll wrote:Using chan (not streaming chan)

Send data
"Close channel"
Send Control token from master thread to slave thread
Wait for and check controltoken sent from the slave

If you want to send more data Before the channel is shut down, you can use a transaction with
master{} / slave{} in XC.
Yes, I'm using a regular CHAN.

How do I send a control token that will shut down the channel, which one?

Do I have to #define it, Prototype?

I'm lost. (nothing new.)
User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

Post by rp181 »

It is still unclear exactly what you are trying to accomplish. Yes, normal channel communications are blocking. If you don't want it to block, you can 1) Use a streaming channel which contains a buffer (channel tx will not block), or 2) Use a select statement:

Code: Select all

select{
   case chan :> dataIn:
        //Do stuff
        break;
   case deault:
       //Do stuff if no data available on the channel
       break;
}
There might be some instructions where you can see if there is data available on the channel as well.
in order to circumvent this in some circumstances the channel would have to be shut down so no thread blocking would occur
You wouldn't shut down the channel (as it already is), you just wouldn't open it, i.e., don't use the channel. This should be controlled through other logic. Based on your conditional circumstance, this could just be an if statement.
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Hi Obtuse,

When people say "channel", they actually mean a lot of different (but
related) things.

On the hardware side, you get a channel end (GETR 2) and set the
destination you want it to send to (SETD). This conceptually creates
a (unidirectional) channel from your core/thread to the destination.
But nothing has happened on the switches yet, no message has been
sent, no routes established.

Then you send something on that channel end (OUT, OUTT, OUTCT).
A (unidirectional) route is established from your chanend to the receiving
chanend. When sending messages between cores, the number of
concurrent such established routes is more limited than e.g. the number
of chanends available. People call an open route a "channel" as well.

You can free an established route by sending a PAUSE control token
(OUTCT 2); you can do that and also make the destination channel
end accept new connections by sending an END (OUTCT 1). The END
token is also delivered to the receiving chanend (PAUSE is not).

Finally, you can free a channel end when you're done with it (FREER).


On the XC level, a channel is a pair of chanends with eachother set
as the destination. The channel is established (GETR, SETD) when the
channel comes into scope in XC, and it is freed when it goes out of
scope. Each :> and <: synchronises by sending and waiting for END
both before and after the IN/OUT (so no route is established when
nothing is being sent right now).


Now, your problem. You want to operate one "server" chanend (on
a "server" thread), which multiple "client" threads can talk to. XC
does not support this as far as I know; you'll have to resort to a
healthy little dose of assembler code.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

You can read more detailed information here:
https://www.xmos.com/published/xmos-xs1 ... ion=latest

Specially chapter 12 and 16 in you case.

A way to not block the waiting thread is as earlier mentioned to use the select statement, including a default:

If a channel becomes active with data an event will be raised.

The default:, will turn off the event handler during the execution of all default instructions until it reaches the select again, turn on the event handler and

If an event is waiting, it will move the program counter and start to execute that case (until the end),
else it will turn of the event again and start to execute the default once more.

Not using the default: statement in a select, the thread will just wait for an event to happen, and move the program counter to the corresponding case.

EDIT: And read segher`s answer above.
If you do not want to use assembler, you have to use one channel for each slave thread in your server thread. (With one case for each channel)
That way each event will correspond to one address for the program counter in the event vector

Code: Select all


chan c[4];
par{
   serverthread(c);
   clientthread_1(c[0]);
   clientthread_2(c[1]);
   clientthread_3(c[2]);
   clientthread_4(c[3]);
}
In this case each channel has 2 channel ends, if you resolve all 4 chanends in the serverthread into a seperate case, and the server will not block if it is idle. Instead it can respond to all 4 client threads, and it will not start to dig it's own grave of nesteled interupts resulting in a stack overflow if the client thread tries to bombard the server with data. Instead the client thread will pause as long as the chanel buffer is full.
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Post by Obtuse »

Thanks All,

I have plenty to mull over.

I tried the SELECT route but found it unsuitable. Perhaps my logic was off and need to revisit that.

Of course more reading can't hurt either.

If I find a solution I'll post it here, or more than likely be back with more questions ( and weird ideas).
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Obtuse wrote:
lilltroll wrote:Using chan (not streaming chan)

Send data
"Close channel"
Send Control token from master thread to slave thread
Wait for and check controltoken sent from the slave

If you want to send more data Before the channel is shut down, you can use a transaction with
master{} / slave{} in XC.
Yes, I'm using a regular CHAN.

How do I send a control token that will shut down the channel, which one?

Do I have to #define it, Prototype?

I'm lost. (nothing new.)
You do not need to do that in XC, the compiler will do that for you, and the Control tokens sent between the threads will also affect the switch, so it closes the channel for you.

All you need to write is:

c<: data;

It will open the channel, send the data, and close the channel again, making the switch free to use for other channel messages from other threads.

(But you have to reliase that a blocking thread is something else that a deadlock in the switch)

A reason to close the channel is to free the switch up for other interthread communication.
In XC it starts to get intresting to send Control tokens "manually" when you use streaming channels, e.g. not closing the channel after a data transmission.