I need better control about task activation so I would like to use
taskInit and taskActivate instead of taskSpawn.
The pStackBase parameter that has to used in taskInit is unclear to me.
Please have a look at my private taskSpawn code snippet if I use the
parameter the right way.
#include "taskLib.h"
int
taskSpawn(char *name, int priority, int options, int stackSize, FUNCPTR
entryPt,
int arg1, int arg2, int arg3, int arg4, int arg5,
int arg6, int arg7, int arg8, int arg9, int arg10){
STATUS status;
WIND_TCB *pTcb;
char *pStackBase;
pTcb = (WIND_TCB *)malloc(sizeof(WIND_TCB) + stackSize);
pStackBase = (char*) pTcb + sizeof(WIND_TCB);
status = taskInit(pTcb,
name,
priority,
options,
pStackBase,
stackSize,
entryPt,
arg1,arg2,arg3,arg4,arg5,
arg6,arg7,arg8,arg9, arg10);
status = taskActivate((int)pTcb);
return (int) pTcb;
}
-martin schrape <sch...@atomika.com>
int myTaskSpawn(char *task_name, int task_prio, int options, int
stack_size,
FUNCPTR fp, int a1, int a2, int a3, int a4, int a5, int
a6,
int a7, int a8, int a9, int a10)
{
int extraSpace = 0;
int stackSize;
WIND_TCB *pTcb;
char *pStackBase, *pStack, *pExtra;
/* calculate extra space (snipped) ..... */
/* calculate needed stack size and align size toa 4 byte boundary */
stackSize = (stack_size + extraSpace + 3) & ~3;
/* allocate stack */
if ((pStack = (char *)malloc(stackSize)) == NULL) {
printf("could not allocate %d bytes stack for %s",
stackSize, task_name);
return ERROR;
}
/* calculate stack base and carve out the TCB of the bottom of the stack
*/
pStackBase = pStack + stackSize - sizeof(WIND_TCB) - extraSpace;
stackSize -= (sizeof(WIND_TCB) + extraSpace);
pExtra = pStackBase;
pTcb = (WIND_TCB *) (pStackBase + extraSpace);
/* put something in your extra space ... */
/* init space for params and TCB with 0 */
memset(pExtra, 0, sizeof(WIND_TCB) + extraSpace);
/* initialize task */
if (taskInit(pTcb, task_name, task_prio, options, pStackBase,
stackSize, fp,
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) == ERROR) {
printf("could not initialize task (Name=%s) - %s",
task_name, strerror(errno));
free(pStack);
return ERROR;
}
/* and activate it */
if (taskActivate((int) pTcb) == ERROR) {
printf("could not activate task (Name=%s) - %s",
task_name, strerror(errno));
free(pStack);
return ERROR;
}
return (int) pTcb;
}
HTH,
Tommy
Martin Schrape wrote:
--
------------------------------------------------------------------------
Thomas Kowatsch | - Senior Software Engineer -
Switching Test Solutions AG | mailto:thomas....@stest.ch
a Wandel & Goltermann Company | web :http://www.stest.com
Friesenbergstr. 75 | Phone : +41 1 454-6731
CH-8055 Zuerich | FAX : +41 1 454-6612
Dear Mr Schrape,
I am responding to your email of Monday 23 March:
> SYSTEM CONFIGURATION :
> HOST : Win NT 4.0
> ARCH : MC68040
> BSP : MV162
>
> DESCRIPTION OF PROBLEM :
> I need better control about task activation so I would like to use taskInit
> and taskActivate instead of taskSpawn.
>
> a) The pStackBase parameter that has to used in taskInit is unclear to me.
> Please have a look at my private taskSpawn if I use the parameter the right
> way.
>
> #include "taskLib.h"
>
> int
> taskSpawn(char *name, int priority, int options, int stackSize, FUNCPTR
> entryPt,
> int arg1, int arg2, int arg3, int arg4, int arg5,
> int arg6, int arg7, int arg8, int arg9, int arg10){
>
> STATUS status;
> WIND_TCB *pTcb;
> char *pStackBase;
>
> pTcb = (WIND_TCB *)malloc(sizeof(WIND_TCB) + stackSize);
>
> pStackBase = (char*) pTcb + sizeof(WIND_TCB);
> status = taskInit(pTcb,
> name,
> priority,
> options,
> pStackBase,
> stackSize,
> entryPt,
> arg1,arg2,arg3,arg4,arg5,
> arg6,arg7,arg8,arg9, arg10);
>
> status = taskActivate((int)pTcb);
>
> return (int) pTcb;
> }
The VxWorks taskSpawn() uses an intermediate function taskCreat(), which is
not documented in the Reference Manual. taskSpawn() calls taskCreat(), then
taskActivate(). It is taskCreat() that calls taskInit().
The essentials of taskCreat() are as follows:
int taskCreat
(
char *name, /* name of new task (stored at pStackBase) */
int priority, /* priority of new task */
int options, /* task option word */
int stackSize, /* size (bytes) of stack needed */
FUNCPTR entryPt, /* entry point of new task */
int arg1, /* task argument one */
int arg2, /* task argument two */
int arg3, /* task argument three */
int arg4, /* task argument four */
int arg5, /* task argument five */
int arg6, /* task argument six */
int arg7, /* task argument seven */
int arg8, /* task argument eight */
int arg9, /* task argument nine */
int arg10 /* task argument ten */
)
{
...
char * pTaskMem; /* pointer to task memory */
char * pStackBase; /* bottom of stack (higher memory address) */
WIND_TCB * pTcb; /* tcb pointer */
...
/* round stacksize up */
stackSize = STACK_ROUND_UP (stackSize);
/* allocate WIND_TCB and stack from task memory partition */
pTaskMem = (char *) objAllocExtra (taskClassId, (unsigned) stackSize,
(void **) NULL);
if (pTaskMem == NULL)
return (NULL); /* allocation failed */
#if (_STACK_DIR == _STACK_GROWS_DOWN)
/*
* A portion of the very top of the stack is clobbered with a FREE_BLOCK
* in the objFree() associated with taskDestroy(). There is no adverse
* consequence of this, and is thus not accounted for.
*/
pStackBase = pTaskMem + stackSize; /* grows down from WIND_TCB */
pTcb = (WIND_TCB *) pStackBase; /* WIND_TCB is after stack */
#else /* _STACK_GROWS_UP */
/*
* To protect a portion of the WIND_TCB that is clobbered with a
FREE_BLOCK
* in the objFree() associated with taskDestroy(), we goose the base of
* tcb by 16 bytes.
*/
pStackBase = pTaskMem + STACK_ROUND_UP (sizeof (WIND_TCB) + 16);
pTcb = (WIND_TCB *) (pTaskMem + 16);
#endif
options |= VX_DEALLOC_STACK; /* set dealloc option bit */
if (taskInit (pTcb, name, priority, options, pStackBase, stackSize,
entryPt,
arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
!= OK)
{
objFree (taskClassId, pTaskMem);
return (NULL);
}
return ((int) pTcb); /* return task ID */
}
I should explain that many VxWorks structures (tasks, semaphores, message
queues, etc.) are generalized with an object layer. The object functions
used in the code not only allocate and free memory, but also update the
object statistics. In the code above:
- objAllocExtra() mallocs memory for the WIND_TCB + the task stack
- objFree() frees the memory
You can see that for the MC68K case (_STACK_GROWS_DOWN), we allocate a single
block of memory with the WIND_TCB at the top (higher address) end of the
block. The stack then grows downward from the WIND_TCB. In your example,
you place the WIND_TCB at the bottom of the memory block. This may have an
effect at the time of task destruction (see below).
> b) Error handling: Do I have to do more clean-up work than freeing the pTcb
> in the example above if taskInit fails?
No.
> c) If I use taskDelete with a task spawned with my private taskSpawn
> routine do I have to do any clean-up. Hopefully not! BUT I really don't
> know how taskDelete can clean up that stuff:
Task destruction is carried out by taskDestroy(), which is called implicitly
at task exit, or explicitly by the functions exit() and taskDelete(). The
way we document taskInit() makes it appear that you can place the WIND_TCB
and the stack in separate memory blocks, but the clean-up carried out by
taskDestroy() assumes them to be in a single contiguous block. Here is an
excerpt from the code:
#if (_STACK_DIR == _STACK_GROWS_DOWN)
/*
* A portion of the very top of the stack is clobbered with a
* FREE_BLOCK in the objFree() associated with taskDestroy().
* There is no adverse consequence of this, and is thus not
* accounted for.
*/
objFree (taskClassId, pTcb->pStackEnd);
#else /* _STACK_GROWS_UP */
/*
* To protect a portion of the WIND_TCB that is clobbered with a
* FREE_BLOCK in this objFree() we previously goosed up the base
of
* tcb by 16 bytes.
*/
objFree (taskClassId, (char *) pTcb - 16);
#endif
The memory that is deallocated is pointed to by pTcb->pstackEnd. So this, too,
assumes the memory layout as set up by taskCreat().
I would advise some caution in the separate use of taskInit() and
taskActivate().
Although they are documented in the Reference Manual, they are not often used,
either within the VxWorks code or in user applications. As we have seen in the
code above, certain assumptions are made about how memory is allocated.
You may be able to get the control you want by spawning a task, and then
immediately suspending it, or having it pend on a semaphore or message queue.
I hope this provides some clarification.
Regards,
Mike Tarlton
--------------------------------------------------------------------
Mike Tarlton
European Technical Support
Wind River Systems
19, avenue de Norvege
ZA de Courtaboeuf 1
91953 Les Ulis Cedex
Tel : +33 1 60 92 63 00
Fax : +33 1 60 92 63 15
Email: mi...@wrsec.fr / sup...@wrsec.fr
--------------------------------------------------------------------