Page 1 of 1

function pointer fifo

Posted: Mon Nov 18, 2013 7:24 am
by sulliwk06
So I'm trying to set up a system where i can queue up functions to be executed from with a specific task. At first I thought of using a complicated system of flags and an array of functions to execute, but then it occurred to me that a fifo is probably the correct way to do it.

I've never used a fifo before but I think I have a problem in the casting the function to an OS_FIFO_EL and back. What happens is when I make the call to myFunction(), I start trapping repeatedly. I know I'm at least passing the function correctly, but when i cast it to put in the queue and pull it out, something breaks. Anyone notice what I'm doing wrong?

Code: Select all

OS_FIFO functionQueue;
void main()
{
	OS_FIFO_EL *func;
	void ( *myFunction )();
	while(1)
	{
		func = OSFifoPend(&functionQueue,0);
		myFunction = (void (*)()) func;
		myFunction();
	}
}
void QueueFunction(void ( *function )())
{
	OSFifoPost(&functionQueue,(OS_FIFO_EL *) function);
}

void InitFunctionFifo()
{
	OSFifoInit(&functionQueue);
}

Re: function pointer fifo

Posted: Mon Nov 18, 2013 11:23 am
by dciliske
I'm 90% certain that you're either not passing a structure containing the function pointer or you're allocating the structure on the stack in the posting context. Either of these will cause you to get a corrupted memory address for the resulting function pointer.

Take a look at the OSFifo example in the RTOS examples for how to do this correctly.

-Dan

Re: function pointer fifo

Posted: Mon Nov 18, 2013 12:23 pm
by sulliwk06
dciliske wrote:I'm 90% certain that you're either not passing a structure containing the function pointer or you're allocating the structure on the stack in the posting context. Either of these will cause you to get a corrupted memory address for the resulting function pointer.

Take a look at the OSFifo example in the RTOS examples for how to do this correctly.

-Dan
It seems you are right, but I can't seem to figure out how to pass the function pointer without it being allocated on the stack. I've tried passing it with QueueFunction(&Function) and that had no effect. I also tried casting it to an OS_FIFO_EL before passing it and that didn't work either. Maybe I'm misunderstanding something fundamental about passing function pointers. Any ideas?

Code: Select all

void Function()
{
	iprintf("print me");
}

void main()
{
	QueueFunction(Function);
}

int QueueFunction(void ( *function )())
{
//	function(); //function can be called from here successfully
	if(!taskInitialized)
	{
		return NOT_INITIALIZED;
	}

	OSFifoPost(&functionQueue,(OS_FIFO_EL *) function);

//	function(); //function cannot be called from here

	return NO_ERROR;
}

I also tried to copy everything exactly from the OSFifo example and it didn't work with functions. Maybe what I'm trying to do isn't possible?

Code: Select all

OSFifoPost(&functionQueue,(OS_FIFO_EL *) &Function);
void ( *myFunction )() = (void (*)()) OSFifoPend(&functionQueue,0);
myFunction();//failed


Update:
I've figured out that the call to OSFifoPost is causing some kind of change in the function pointer. Is this what you would expect to happen? I would have thought that it shouldn't change anything.

Code: Select all

int QueueFunction(void ( *function )())
{
	if(!taskInitialized)
	{
		return NOT_INITIALIZED;
	}

//	OSFifoPost(&functionQueue,(OS_FIFO_EL *) function);
	OSFifoPost(&functionQueue,(OS_FIFO_EL *) &taskInitialized);  //post something other than the function pointer

	function(); //executes properly now that it isn't being posted to the queue, previously it would fail here

	return NO_ERROR;
}

Re: function pointer fifo

Posted: Mon Nov 18, 2013 1:56 pm
by dpursell
sulliwk06 wrote: Update:
I've figured out that the call to OSFifoPost is causing some kind of change in the function pointer. Is this what you would expect to happen? I would have thought that it shouldn't change anything.

Code: Select all

int QueueFunction(void ( *function )())
{
	if(!taskInitialized)
	{
		return NOT_INITIALIZED;
	}

//	OSFifoPost(&functionQueue,(OS_FIFO_EL *) function);
	OSFifoPost(&functionQueue,(OS_FIFO_EL *) &taskInitialized);  //post something other than the function pointer

	function(); //executes properly now that it isn't being posted to the queue, previously it would fail here

	return NO_ERROR;
}

According to the docs and example, the OS_FIFO objects expect a struct where the first element if a void*, and the structs use that pointer for internal bookkeeping. So yes, I think it's expected that the value changes. You need to provide a struct with a void* and then your function pointer.

Try something like this:

Code: Select all

typedef struct
{
  void* internalBookkeeping;  // don't use this yourself at all
  void (*function)(); // here's your function pointer
} MyQueueStruct;

int QueueFunction(void (*function)())
{
  MyQueueStruct* item;

  if (!taskInitialized)
  {
    return NOT_INITIALIZED;
  }

  // I use C++ so forgive me if my malloc call is wrong
  // If you don't want to use dynamic memory allocation you can use global variables instead,
  // but if I'm reading the docs correctly you *cannot* just create a MyQueueStruct on the stack here
  // because the memory would be lost as soon as this function exits. If you use malloc, make sure to
  // call free after you pull it out of the FIFO or you will have a memory leak
  item = (MyQueueStruct*)malloc(sizeof(MyQueueStruct));
  item->function = function;

  OSFifoPost(&functionQueue, (OS_FIFO_EL*) item);

  return NO_ERROR;
}

Re: function pointer fifo

Posted: Mon Nov 18, 2013 2:52 pm
by Ridgeglider
In addition to dciliske's advice, take a look at the C:\nburn\docs\NetworkProgrammersGuide\NNDK Netburner Programmer's Manual.PDF FIFO example, in my docs, section 5.1.4. It passes a trivial struct on a fifo of statically allocated maximum size. It includes a simple way to check whether space is left in the fifo and if so, adds to the fifo, and if not, produce an error message. Modify the example struct to meet your needs, but keep the first element as the examples define it if you want to use their approach to ensuring empty space. On a somewhat unrelated note, you may want to modify the struct using something like:
struct __attribute__ ((__packed__)) MyStruct_t {
// your elements here
}

if you care about the offsets into your struct(s) being the same in various instances.

Re: function pointer fifo

Posted: Tue Nov 19, 2013 5:32 am
by sulliwk06
Thank you all for your help, I didn't realize that a FIFO needed a persistent struct to reference with a void pointer in it. I've got it working properly now.

Re: function pointer fifo

Posted: Tue Nov 19, 2013 9:11 pm
by pbreed
I'd use the queue rather than the fifo....

Exact same functionality, but the queu holds the storage, vs counting on having an element in the structure for the fifo.
The Fifo is really a rather special class for managing network and other variable length buffer blocks.


Paul