Fail to free sem/mbox using tm4c1294

jinwon wrote on Thursday, February 19, 2015:

I am using tm4c1294+lwip1.4.1+FreeRTOS.

As netconn_alloc() is called for socket communication, it allocates an unused semaphore. the number of semaphore is defined as SYS_SEM_MAX, so it can not be over SYS_SEM_MAX. However, as semaphores are allocated continuously it reaches SYS_SEM_MAX and stop working since I gues sys_sem_free() does not deallocate it properly

Here is function that creates a semaphore implemented in sys_arch.c

err_t
sys_sem_new(sys_sem_t *sem, u8_t count)
{

  void *temp;
  u32_t i;

  /* Find a semaphore that is not in use. */
  for(i = 0; i < SYS_SEM_MAX; i++) {
    if(sems[i].queue == 0) {
      break;
    }
  }

if(i == SYS_SEM_MAX) {
#if SYS_STATS
    STATS_INC(sys.sem.err);
#endif /* SYS_STATS */
    return ERR_MEM;
  }

  /* Create a single-entry queue to act as a semaphore. */
#if RTOS_FREERTOS
  sem->queue = xQueueCreate(1, sizeof(void *));
  if(sem->queue == NULL) {
#endif /* RTOS_FREERTOS */

#if SYS_STATS
    STATS_INC(sys.sem.err);
#endif /* SYS_STATS */
    return ERR_MEM;
  }

/* Acquired the semaphore if necessary. */
if(count == 0) {
temp = 0;
xQueueSend(sem->queue, &temp, 0);
}

 /* Update the semaphore statistics. */
#if SYS_STATS
  STATS_INC(sys.sem.used);
#if LWIP_STATS
  if(lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {
    lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
  }
#endif
#endif /* SYS_STATS */

  /* Save the queue handle. */
  sems[i].queue = sem->queue;

  /* Return this semaphore. */
  return (ERR_OK);
}

Here is another function that frees semaphore implemented in sys_arch.c

void
sys_sem_free(sys_sem_t *sem)
{
  
  /* Delete Sem , By Jin */
  vQueueDelete(sem->queue);
/* Clear the queue handle. */
  sem->queue = 0;

 /* Update the semaphore statistics. */
#if SYS_STATS
  STATS_DEC(sys.sem.used);
#endif /* SYS_STATS */

}

Whenever netconn_free() is called sys_sem_free() deallocates the semaphore, but it does not free the semaphore assigned in sem[] array.

I added vQueueDelete(sem->queue); that was suggested by someone, but still all same.

Not only functions creates/frees semaphore but also functions handling mbox are same as functions above, so functions handling mbox could be wrong as well.

Someone already reported this issue to TI, but it seems they have not solved the problems yet.

Therefore, I may need to implement my own functions handling semaphore/mbox in sys_arch.c, but I don’t have any clues so far.

Can anyone give me any ideas? or anything?

Thanks, Jin

rtel wrote on Thursday, February 19, 2015:

I’m afraid we cannot provide direct support for lwIP - which is one of the reasons we created our own TCP/IP. However there is a reference lwIP integration in the FreeRTOS Interactive site. Note it is quite old though, and the CLI included in the project is not the same as the FreeRTOS+CLI project. Maybe it will help:

http://interactive.freertos.org/entries/20290712-FreeRTOS-Win32-project-with-lwIP-web-server

Regards.

jinwon wrote on Thursday, February 26, 2015:

Thanks for replying.

I am looking at source codes that you linked,but it’s quite different.
I edited my question that is different from the last time I posted.
If you have any ideas please let me know.

Thanks,
Jin

rtel wrote on Friday, February 27, 2015:

Well, we have a reference implementation, you can choose to use it, or you can choose to ignore it. In the latter case I’m afraid we cannot look through your code and make suggestions for you as lwIP is not our product. That said:

Are you sure the function that deletes the semaphore is ever being called? Mistakes in the porting or usage may just mean the stack is not being used correctly. The reason I ask is that, if you have read the FAQ pages you will have by now defined configASSERT() to assist with your debugging…and if you have defined configASSERT than your sys_sem_free() function will trigger two asserts because you are first wiping over the pointer to the require memory by setting it to 0 (and in so doing leaking the memory - which could well be the route cause of your problem), then second pass the pointer which is now set to 0 (NULL) into a function that will try and free it.

Regards.

jinwon wrote on Friday, February 27, 2015:

Sorry, I didn’t update sys_sem_free() in my source codes and it does call this function.

  vQueueDelete(sem->queue);
  sem->queue = 0;

This is not working either.

sys_arch.c is implemented by TI and I am suspicious about mismatch between sems[] used as a global array to hold the memory for the available semaphores and *sem in sys_sem_free(sys_sem_t *sem);therefore, even if *sem is set to NULL in sys_sem_free() the semaphores in sems[] are not deleted synchronously.

I have not used configASSERT() since freeRTOS is new to me, so I need to take a look at how to use it.

Thank you for answering.
Jin

jinwon wrote on Friday, February 27, 2015:

I have hit compile errors as I add configASSERT() in FreeRTOSConfig.h

So I directly use the function in two places of codes instead of the macro

if(sem->queue == 0)
{
	//UARTprintf("Assert 1 called !!~~\n");
	taskDISABLE_INTERRUPTS();
	for( ;; )
	{

	}
}

Well, nothing goes into the above assert function. the application still stops as semaphores hit the max.

Thanks,
Jin

davedoors wrote on Saturday, February 28, 2015:

What were the compiler errors?

jinwon wrote on Monday, March 02, 2015:

HI,

There are a couple of undefined symbol(configMAX_SYSCALL_INTERRUPT_PRIORITY) errors in portasm.asm and other files that use configASSERT()

However, I can directly use codes instead of the macro. It could be nice to use the macro but my issue is not this but allocating/deallocating semaphore like I said above.

Thanks,
Jin

davedoors wrote on Monday, March 02, 2015:

You are using a Cortex-M4, right? So what is portasm.asm? Its not a file from the FreeRTOS download.

jinwon wrote on Monday, March 02, 2015:

Hi,

I am using Cortex M4,and portasm.asm is in the TM4C1294 package (FreeRTOS/Source/portable/CCS/ARM_CM4F/portasm.asm)

I don’t get “it’s not a file from the FreeRTOS download”

Thanks,

rtel wrote on Monday, March 02, 2015:

I don’t get “it’s not a file from the FreeRTOS download”

There is no CCS port for the M4 in the FreeRTOS download, so it is not
an official FreeRTOS file.

There may well be a CCS port in the coming months though.

Regards.

jinwon wrote on Wednesday, March 04, 2015:

I changed mainly sys_arch.c/.h implemented in the linked source codes to see how that goes. The problem was not to free semaphores stored in global array as a result it reached the maximum size of array (SYS_SEM_MAX) and stop allocating a new semaphore.

the linked source codes are not using a global array containing semaphores. It just uses a single binary semaphore.

err_t sys_sem_new( sys_sem_t *pxSemaphore, u8_t ucCount )
{
err_t xReturn = ERR_MEM;

//	vSemaphoreCreateBinary( ( *pxSemaphore ) );
	*pxSemaphore = xSemaphoreCreateBinary();

	if( *pxSemaphore != NULL )
	{
		if( ucCount == 0U )
		{
			xSemaphoreTake( *pxSemaphore, 1UL );
		}

		xReturn = ERR_OK;
		SYS_STATS_INC_USED( sem );
	}
	else
	{
		SYS_STATS_INC( sem.err );
	}

	return xReturn;
}

Free used semaphores:

void sys_mutex_free( sys_mutex_t *pxMutex )
{
	SYS_STATS_DEC( mutex.used );
	vQueueDelete( *pxMutex );

}

The tasks running on the TM4C1294 keep on socket communicating with a server in every a second and less than that.

However every time calling xSemaphoreCreateBinary() keeps increasing the address of memory up to allowable usage of memory, and then fail to allocate a new one, although sys_sem_free() is called at the end of socket communication.

I feel like need to rewind/reuse semaphores instead of increasing the address of memory, which leads me back to the global array containing semaphores implemented in Tiva C.

Any advices or ideas?

Regards,
Jin

rtel wrote on Thursday, March 05, 2015:

Let me try and simplify and take lwIP out of the equation.

Are you saying that vQueueDelete() is called the same number of times as
xSemaphoreCreateBinary(), so every semaphore that is created is also
deleted, but you are running out of heap space anyway?

Please remember you are using third party code, a third party port and a
third party demo - we are happy to provide ‘generic’ FreeRTOS help, but
cannot vouch for or research any of the code you are using.

Regards.

jinwon wrote on Thursday, March 05, 2015:

That’s correct.

As I used safeRTOS, it did not happen. I asked if xSemaphoreCreateBinary() keeps increasing the address of memory every time it is called, so without rewinding/reusing the memory allocation of xQueueHandler it will eventually run out of heap.

Thanks,

vinimac wrote on Thursday, March 26, 2015:

Hi Jin, I’m having the exact same problem.

I found the root of the problem and a solution using original code. As you said “Whenever netconn_free() is called sys_sem_free() deallocates the semaphore, but it does not free the semaphore assigned in sem[] array.”

So, what I did was that:

/**
 * Destroys a semaphore.
 *
 * @param sem is the semaphore to be destroyed.
 */
void
sys_sem_free(sys_sem_t *sem)
{
        u32_t i;
 
          /* Find a semaphore that is in use. */
          for(i = 0; i < SYS_SEM_MAX; i++) {
            if(sems[i].queue == sem->queue) {
              break;
            }
          }
 
        /* Delete Sem , By Jin */
          vQueueDelete(sem->queue);
 
          /* Clear the queue handle. */
          sem->queue = 0;
          /* Clear the queue handle in global array. */
          sems[i].queue = 0;
 
          /* Update the semaphore statistics. */
        #if SYS_STATS
          STATS_DEC(sys.sem.used);
        #endif /* SYS_STATS */
}

And the same thing to mbox:

/**
 * Destroys a mailbox.
 *
 * @param mbox is the mailbox to be destroyed.
 */
void
sys_mbox_free(sys_mbox_t *mbox)
{
        u32_t i;
  /* There should not be any messages waiting (if there are it is a bug).  If
     any are waiting, increment the mailbox error count. */
#if RTOS_FREERTOS
  if(uxQueueMessagesWaiting(mbox->queue) != 0) {
#endif /* RTOS_FREERTOS */
 
#if SYS_STATS
    STATS_INC(sys.mbox.err);
#endif /* SYS_STATS */
  }
 
        /* Find a mailbox that is in use. */
        for(i = 0; i < SYS_MBOX_MAX; i++) {
          if(mboxes[i].queue == mbox->queue) {
                break;
          }
        }
 
  /* Delete Sem , By Jin */
    vQueueDelete(mbox->queue);
  /* Clear the queue handle. */
  mbox->queue = 0;
  /* Clear the queue handle in global array. */
  mboxes[i].queue = 0;
 
  /* Update the mailbox statistics. */
#if SYS_STATS
   STATS_DEC(sys.mbox.used);
#endif /* SYS_STATS */
}

This solved the problem. Now I can connect as many times as necessary.