Author Topic: handle tcp data until a task is ready  (Read 9471 times)

Offline mvaurelien

  • Newbie
  • *
  • Posts: 8
    • View Profile
handle tcp data until a task is ready
« on: August 27, 2010, 03:51:10 PM »
Hi Mark,

Here is my case :
 I handle ethernet data from my TCP listener, then I start to analyze data to know which other task need to receive this data. I had big queues in the tasks and I limited TCP_DEF_MTU in order to make it smaller than the task buffer. So if my handler is called once, the destination task receive all data. If the ethernet data comes slowly, the destination task is still launched between every handler so everything is still good. The problem appears when data comes very quickly, the handler is launched more than once and when it try to send data to the task, the queue is full.

I need to call the handler again, with the same data, when destination task has freed it queue. I'm sure other people may have the same issue but I can't find in the docs or in the forum how easily make it wait to try again, and never lost data.

Thanks if you could give me some advice.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: handle tcp data until a task is ready
« Reply #1 on: August 27, 2010, 08:48:09 PM »
Hi Aurelien

I haven't heard of this problem before although I am aware that the Ethernet task doesn't limit the number of reception frames that it handles each time it is called. Possibly most people do all of the processing in the callback, which makes it less noticeable (?).

However there is a simple technique that should ensure that this doesn't happen in your case, when sending reception date for processing by another task via its (limited length) input queue.

In Ethernet.c try adding the following

                fnFreeBuffer(Ethernet_handle, cEthernetBuffer);          // free up the receiver buffer since we have completed working with it
#ifdef ETHERNET_RELEASE_AFTER_EVERY_FRAME                                // {6}
                uTaskerStateChange(OWN_TASK, UTASKER_ACTIVATE);          // schedule the task to check the input once more after allowing other tasks to run
                return;                                                  // quit for the moment
#endif


Here there is a define called ETHERNET_RELEASE_AFTER_EVERY_FRAME which you can add to config.h with the following comment:
#define ETHERNET_RELEASE_AFTER_EVERY_FRAME                           // handle only one Ethernet reception frame at a time and allow other tasks to be schedule in between

Rather than allowing the Ethernet task to handle receptions until there are no more waiting, it instead allows it to handle one reception frame. It sets the task's state to UTASKER_ACTIVATE, which means that it will be forced to run again (once). The task is quit, allowing other tasks in the system to be scheduled if required, including your task handling the TCP reception content, and then enter again to check whether there are further waiting reception frames (which may have been originally waiting or could have arrived in the meantime). If there is nothing waiting it sleeps again.

This means that your task will in fact only ever have one message in its input queue from the Ethernet task (which is calling your listener when handling the TCP frame).

It would be possible to use a counter to allow a certain maximum number of Ethernet frame to be treated in each Ethernet task activation but I think that one frame at a time is in fact adequate generally.

Regards

Mark


Offline mvaurelien

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: handle tcp data until a task is ready
« Reply #2 on: August 30, 2010, 09:39:29 AM »
Thanks again Mark, it's perfect with this technique !

Offline mhoneywill

  • Full Member
  • ***
  • Posts: 173
    • View Profile
Re: handle tcp data until a task is ready
« Reply #3 on: August 31, 2010, 12:39:16 PM »
Hi Mark,

Just processing one reception Frame seems like a sensible addition to the stack, is this something that you are building into the stack as standard?

Are there any issues you can see with leaving ETHERNET_RELEASE_AFTER_EVERY_FRAME defined by default?

Cheers

Martin

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: handle tcp data until a task is ready
« Reply #4 on: August 31, 2010, 03:15:54 PM »
Hi Martin

I have put this option in my code base. It is in fact something that I was thinking of doing for some time.
Also I don't see any real disadvantage of this as being a default setting.

Regards

Mark

Offline mhoneywill

  • Full Member
  • ***
  • Posts: 173
    • View Profile
Re: handle tcp data until a task is ready
« Reply #5 on: August 31, 2010, 06:55:38 PM »
Is it worth making the define something like ETHERNET_PROCESS_EVERY_FRAME and then doing

#ifndef ETHERNET_PROCESS_EVERY_FRAME                                // {6}
                uTaskerStateChange(OWN_TASK, UTASKER_ACTIVATE);          // schedule the task to check the input once more after allowing other tasks to run
                return;                                                  // quit for the moment
#endif

Then the change is added by default and you don't need to modify config.h

Regards

Martin

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: handle tcp data until a task is ready
« Reply #6 on: August 31, 2010, 08:42:22 PM »
Hi Martin

I may set it active in the reference project. This means that new users will automatically be using it.

However I prefer not to automatically activate it in existing projects which update the TCP/IP directory but keep their original config.h since this would result in a change of program flow. Although this will probably not generally result in a change in behavior I think that active projects should decide for themselves whether to activate this or other new functionality. Upgrades should improve any known deficiencies (bug fixes etc.) and add optional new features but not necessarily require the user (where realistic) to have to accept such changes, which may possibly have side-effects and thus cause additional work to solve. If a project actively enables a new option it is then performed as the result of an active decision, accepting the potential side-effects and also being aware of exactly what was modified - this also makes it easier to revert back to the original state in case of unexpected behavior. The new option will of course be mentioned in the release notes ;-)

Regards

Mark