This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/AM3358: GateMutex causing exit

Part Number: AM3358

Tool/software: TI-RTOS

Good morning,

I recently tried adding GateMutexPri's to a project to control access to a resources such as the file system, UART's, Ethernet etc and what I have done seems to work well on first inspection but when left for prolonged periods of time it goes into _exit(int) and I get the red text below in the window

"Can't find a source file at "/db/ztree/library/trees/xdctargets/xdctargets-j04/src/gnu/targets/arm/rtsv7A/syscalls.c"
Locate the file or edit the source lookup path to include its location."

The ROV does not report an exception as is usually the case with this kind of reaction.  I am using XDCtools ver 3.31.0.24_core, SYS/BIOS ver 6.42.3.35, compiler GNU v4.8.4 (Linaro) and finally CCS ver 6.1.1.00022.

Below is the code I am using to setup the GateMutexPri along with a semaphore version which does work absolutely fine as far as i can tell.

//#define USE_GATE_MUTEX_PRI
#ifdef USE_GATE_MUTEX_PRI
		IArg gate_key = 0;
		GateMutexPri_Handle gate = NULL;
#else
		static Semaphore_Handle sem = NULL;
#endif


int32_t OxTS_fs_init(void)
{
#ifdef USE_GATE_MUTEX_PRI
	gate =  SetupGateMutex();
#else
	sem = SetupSem(SEM_MODE_COUNTING);
	FreeResource();
#endif

	return 0;
}

static void ClaimResource(void)
{
#ifdef USE_GATE_MUTEX_PRI
	gate_key =  GateMutexPri_enter(gate);
#else
	Semaphore_pend(sem, BIOS_WAIT_FOREVER);
#endif
	return;
}

static void FreeResource(void)
{
	if(dont_offer_resource == 0)
	{
#ifdef USE_GATE_MUTEX_PRI
		GateMutexPri_leave(gate, gate_key);
#else
		Semaphore_post(sem);
#endif
	}
	return;
}

The code is pretty simple so i am struggling to see what I could have done wrong or what i can try differently, all i have tried is having the key as a local instead of global and it made no difference.

Any help or ideas gratefully revived.

Thanks

Sean

  • The RTOS team have been notified. They will respond here.
  • fyi my GateMutex setup function looks like this:

    GateMutexPri_Handle SetupGateMutex(void)
    {
    	GateMutexPri_Handle gate_h = NULL;
    	gate_h = GateMutexPri_create(NULL, NULL);
    	assert(gate_h != NULL);
    	return gate_h;
    }

  • Hi Sean,

    Where is gate_key defined? It should be a local to ClaimResource and the value returned from the API. Then the value should be passed into FreeResource. The key allows gates to be recursive, so the same thread can call the enter multiple times (note: it then needs to leave the gate the same number of times).

    Todd

  • Hi Todd,

    In the example above it is a global, i did try it as a local and it didn't seem to help but I will change the code as you suggested as it sounds like that is how it should be and then try again.

    Thanks

    Sean
  • Sounds good. Let me know what happens.
  • Hi Todd, 

    nope didn't help.  i changed the functions to the below and it still crashed after a few hours.  btw at this point there is only one context accessing what the GateMutesPri's are protecting.

    static IArg ClaimResource(void)
    {
    #ifdef USE_GATE_MUTEX_PRI
    	return GateMutexPri_enter(gate);
    #else
    	Semaphore_pend(sem, BIOS_WAIT_FOREVER);
    #endif
    	return 0;
    }
    
    static void FreeResource(IArg key)
    {
    #ifdef USE_GATE_MUTEX_PRI
    	GateMutexPri_leave(gate, key);
    #else
    	Semaphore_post(sem);
    #endif
    	return;
    }

    thanks

    Sean

  • Bummer. What is the state of the tasks when this occurs? Do you have asserts enabled in the kernel (i.e. BIOS.assertsEnabled = true; in the .cfg file)?
  • Hi Todd,

    The below code causes the crash reliably and instantly.

    static GateMutexPri_Handle gate = NULL;
    
    static void Task(UArg arg0, UArg arg1) {
    	IArg key = GateMutexPri_enter(gate);
    	GateMutexPri_leave(gate, key);
    }
    
    void idle_function(void) {
    	Task_Handle task = NULL;
    
    	// Set up and enter the gate
    	gate = GateMutexPri_create(NULL, NULL);
    	assert(gate != NULL);
    	IArg key = GateMutexPri_enter(gate);
    
    	//Start the task
    	Task_Params taskParams;
    	Task_Params_init(&taskParams);
    	taskParams.priority = 6;
    	task = Task_create((Task_FuncPtr)Task, &taskParams, NULL);
    	assert(task != NULL);
    
    	GateMutexPri_leave(gate, key);	// Never returns from here or goes back into Task as it should
    	while(1);
    }

    In happens when the GateMutexPri_leave is executed in the idle loop and it never gets back into the task.  Looking in ROV you can see that the GateMutexPri is with the idle loop and its current priority is 6 because the task has requested the gate.  No exception is shown and in the task view ti shows the idle loop has been preempted and has a priority of 6 and that the other task is blocked.  There was another access to the GatMutexPri's in my full code I had missed as you can probably guess it was in the idle loop hence how i discovered this.

    I have tried:

    • Changing the idle loop to a priority 1 task and it worked fine.
    • Just running the idle loop through without starting the task and it worked fine
    • Changing the GateMutexPri to standard GateMutex, again this works fine

    So it seems the issue is when the idle task inherits a higher priority due to the gate request from the task it causes SYS/BIOS to crash.  not sure what else i can do to investigate this, if you could suggest a fix that would be great and for now I will just have to work around it.

    Cheers

    Sean

  • Hi Sean,

    While it's strange to have GateMutexPri_enter in an Idle function, I was not able to reproduce your problem. Your example run fine. I had nothing but the myIdleFunc function plugged into Idle (in the .cfg file). I did increase the heap and idle stack size to make sure I had no allocation or stack issues.

    I ran the example and had a breakpoint the the GateMutexPri_leave in the Idle function.

    Note: I had already hit the breakpoint at GateMutexPr_enter in the in the Task function.

    Here is the Task->Detailed view

    Again weird that Idle is at priority 6, but this should not cause a problem.

    When I ran, I hit the breakpoint at GateMutexPri_leave in the Task function. Again the tasks looked fine.

    I continued and when I halted I see the Task terminated and Idle stuck in the while(1) loop. 

    What crash are you seeing with this setup?

    Todd

  • Hi Todd,

    It just breaks is _exit(int) and I get the red text below in the window.

    "Can't find a source file at "/db/ztree/library/trees/xdctargets/xdctargets-j04/src/gnu/targets/arm/rtsv7A/syscalls.c"
    Locate the file or edit the source lookup path to include its location."

    Did you try this with the same versions of SYS/BIOS etc as me?

    Cheers

    Sean
  • Yes, I used the same version. I had a slightly different XDCtools and CCS versions, but that should not have mattered.

    Can you confirm that you have enough heap and the stack is not blown? Note the task stack is being allocated from the heap since you did not provide it. The heap size is set via the BIOS.heapSize variable in the .cfg file. For example:

    BIOS.heapSize = 4096;
  • Hi Todd,

    Yes we have 128MB, BIOS.heapSize = 128*1024*1024; //128M.

    Sean
  • That should be big enough:)

    Can you try my exact steps with the same breakpoints that I have above. Do you hit all 4 of them? Then after the last breakpoint, the target should just be running and if you halt, it will be in Idle at the while(1);.
  • Tried that and same issue I also stripped back everything else out of my project to just have that code as before I had some classes etc that would have ran before main and no luck.  Tried changing to c instead of cpp and swapping to the TI compiler and the same behaviour all the time

    This is my config file btw

    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    var Diags = xdc.useModule('xdc.runtime.Diags');
    var Error = xdc.useModule('xdc.runtime.Error');
    var Log = xdc.useModule('xdc.runtime.Log');
    var LoggerBuf = xdc.useModule('xdc.runtime.LoggerBuf');
    var Main = xdc.useModule('xdc.runtime.Main');
    var SysMin = xdc.useModule('xdc.runtime.SysMin');
    var System = xdc.useModule('xdc.runtime.System');
    var Text = xdc.useModule('xdc.runtime.Text');
    var GateAll = xdc.useModule('ti.sysbios.gates.GateAll');
    var GateMutexPri = xdc.useModule('ti.sysbios.gates.GateMutexPri');
    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    var Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
    var Memory = xdc.useModule('xdc.runtime.Memory');
    var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
    var ti_sysbios_family_arm_a8_intcps_Hwi = xdc.useModule('ti.sysbios.family.arm.a8.intcps.Hwi');
    var Idle = xdc.useModule('ti.sysbios.knl.Idle');
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
    var Cache = xdc.useModule('ti.sysbios.family.arm.a8.Cache');
    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
    
    var ti_sysbios_family_arm_a8_TimestampProvider = xdc.useModule('ti.sysbios.family.arm.a8.TimestampProvider');
    ti_sysbios_family_arm_a8_TimestampProvider.autoRefreshEnable = false;
    
    /*
     * Disable modules enabled by default we do not want.
     */
    BIOS.clockEnabled = false;
    BIOS.swiEnabled = false;
    
    /*
     * Uncomment this line to globally disable Asserts.
     * All modules inherit the default from the 'Defaults' module.  You
     * can override these defaults on a per-module basis using Module.common$. 
     * Disabling Asserts will save code space and improve runtime performance.
    Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF;
     */
    
    /*
     * Uncomment this line to keep module names from being loaded on the target.
     * The module name strings are placed in the .const section. Setting this
     * parameter to false will save space in the .const section.  Error and
     * Assert messages will contain an "unknown module" prefix instead
     * of the actual module name.
    Defaults.common$.namedModule = false;
     */
    
    /*
     * Minimize exit handler array in System.  The System module includes
     * an array of functions that are registered with System_atexit() to be
     * called by System_exit().
     */
    System.maxAtexitHandlers = 4;       
    
    /* 
     * Uncomment this line to disable the Error print function.  
     * We lose error information when this is disabled since the errors are
     * not printed.  Disabling the raiseHook will save some code space if
     * your app is not using System_printf() since the Error_print() function
     * calls System_printf().
    Error.raiseHook = null;
     */
    
    /* 
     * Uncomment this line to keep Error, Assert, and Log strings from being
     * loaded on the target.  These strings are placed in the .const section.
     * Setting this parameter to false will save space in the .const section.
     * Error, Assert and Log message will print raw ids and args instead of
     * a formatted message.
    Text.isLoaded = false;
     */
    
    /*
     * Uncomment this line to disable the output of characters by SysMin
     * when the program exits.  SysMin writes characters to a circular buffer.
     * This buffer can be viewed using the SysMin Output view in ROV.
    SysMin.flushAtExit = false;
     */
    
    //var heapSection = new Program.SectionSpec();
    //heapSection.loadSegment = "DDR3_HI";
    //heapSection.type = "NOINIT";
    //heapSection.type = "NOLOAD";
    
    /* Create heap as global variable so it can be used in C code and set it as the default */
    //var heapMemParams = new HeapMem.Params();
    //heapMemParams.size = 128*1024*1024;
    //heapMemParams.sectionName = "heapSection";
    //Program.global.noInitHeap = HeapMem.create(heapMemParams);
    //Memory.defaultHeapInstance = Program.global.noinitHeap;
    
    //Program.sectMap[".heapSection"] = "DDR3_HI";
    
    //HeapMem.common$.instanceSection = ".heapStatic";
    //Program.sectMap[".heapStatic"] = new Program.SectionSpec();
    //Program.sectMap[".heapStatic"].loadSegment = "DDR3_HI";
    //Program.sectMap[".heapStatic"].runSegment = "DDR3_HI";
    //Program.sectMap[".heapStatic"].type = "NOINIT";
    //Program.sectMap[".heapStatic"].type = "NOLOAD";
    
    /*
     * Build a custom SYS/BIOS library from sources.
     */
    BIOS.libType = BIOS.LibType_Custom;
    
    /* Circular buffer size for System_printf() */
    SysMin.bufSize = 0x200;
    
    /* 
     * Create and install logger for the whole system
     */
    var loggerBufParams = new LoggerBuf.Params();
    loggerBufParams.numEntries = 16;
    var logger0 = LoggerBuf.create(loggerBufParams);
    Defaults.common$.logger = logger0;
    Main.common$.diags_INFO = Diags.ALWAYS_ON;
    
    System.SupportProxy = SysMin;
    Defaults.common$.diags_ASSERT = Diags.ALWAYS_ON;
    Defaults.common$.diags_INTERNAL = Diags.ALWAYS_ON;
    
    /* 
     * Cache and MMU setup
     */
    
    // Enable the cache
    Cache.enableCache = true;
    
    // Enable the MMU (Required for L1/L2 data caching) and configure the memory areas
    Mmu.enableMMU = true;
    
    // Force peripheral section to be NON cacheable
    var Peripheral_Attrs = {
        type : Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
        tex: 0,
        bufferable : false, // bufferable
        cacheable : false, // cacheable
        shareable : false, // shareable
        noexecute : true, // not executable
    };
    
    // Set the descriptor for each entry in the address range
    for (var i=0x44000000; i < 0x80000000; i = i + 0x00100000) {
        // Each 'SECTION' descriptor entry spans a 1MB address range
        Mmu.setFirstLevelDescMeta(i, i, Peripheral_Attrs);
    }
    
    // descriptor attribute structure
    var DDR3_Attrs = {
        type: Mmu.FirstLevelDesc_SECTION,  // SECTION descriptor
        tex: 0x1,
        bufferable: true,                  // bufferable
        cacheable: true,                   // cacheable
    };
    
    // Set the descriptor for each entry in the address range
    for (var i=0x80000000; i < 0xc0000000; i = i + 0x00100000) {
        // Each 'SECTION' descriptor entry spans a 1MB address range
        Mmu.setFirstLevelDescMeta(i, i, DDR3_Attrs);
    }
    
    /*
     * The BIOS module will create the default heap for the system.
     * Specify the size of this default heap.
     */
    BIOS.heapSize = 128*1024*1024;	//128M
    
    Idle.idleFxns[0] = "&idle_function";
    
    BIOS.cpuFreq.lo = 1000000000;
    Task.idleTaskStackSize = 8*1024*1024;	//8M
    Task.defaultStackSize = 4*1024;
    
    /* System stack size (used by sISRs and Swis) */
    Program.stack = 1*1024*1024;	//1M
    
    Program.sectMap[".c_int00"] = new Program.SectionSpec(); 
    Program.sectMap[".c_int00"].loadAddress = 0x80000000; 
    Program.sectMap[".c_int00"].runAddress = 0x80000000;
    

  • Which one of the breakpoints was not hit?
  • Hi Todd so it gets to the leave in the idle loop and then when you step or run into that you get the exit so it doesn't hit the leave in the task and doesn't get to the while(1).

  • Hi Sean,

    Sorry, I did not quite understand your description. Let's put labels on the break-points.

    You should hit the breakpoints in this order if you are running between breakpoints. Which breakpoint are you not hitting?

    Todd

  • Hi Todd,

    I am not hitting 3 or 4 as it exits inside the leave call at 2 in the idle loop.

    Sean

  • What do you mean by "it exits inside the leave call"? Where does it go? Is there something else running that is taking the processor (e.g. a higher priority task or Hwi) or does it go into the weeds? Does this occur ever time with this simple test case?