VxWorks / Tornado II FAQ


5. VxWorks Questions

5.1 C++ issues

5.2 Communication problems

5.3 Interrupts

5.4 LoadModule problems

5.4A malloc and other memory issues

5.5 pthreads

5.6 Reboot

5.7 Semaphores

5.8 Simulator (VxSim)

5.9 Task related items

5.10 Time related items

5.11 Wind Web Server related items

5.12 Zinc/windML related items

5.13 Other items

5.14 VxWorks AE questions

Index


5. VxWorks Questions

5.1 C++ issues

Q: When I download some C++ code my target crashes, even when I don't start anything.

A: What is probably happening is any static or global classes that you have defined are having their constructors called. The class is actually being instantiated when the file is loaded into memory, thus the constructor is called.
(From: nick_nw@my-deja.com)


Q: What is the syntax of "taskSpawn" for spawning a method of an object (C++) as a task.

A: See question 5.9-F.


Q: How can I call a C++ function from within a C-file?

A: See question 1.1-H.


Q: What is the preferred extension for C++ files?

A: For C++-files you can use .C (compared to .c for C-files), .cc, .cpp or .cxx. Don't use .C (uppercase) as an extension for C++. It works ok on Unix hosts, but won't work if you develop on Windoze... for obvious reasons.
The ending I prefer is .cxx. Certain MS compilers don't like .cc, GCC doesn't (or at least didn't in the past) like .cpp. Both take .cxx.
(From: engineer_scotty, sj@aracnet.com)


Q: Gotcha with C++ static constructors and GCC 2.95.x (PPC)

A: After several hours of debugging and pulling out my hair :), I've just found a (afaik undocumented) bug with GCC 2.95.x which may cause static constructors/destructors to NOT work when loaded onto the target using the target-based loader (the ld/loadModule) commands. Don't know if this effects the host-based shell or not.

Essentially, the problem is as follows: The munch script can be told to produce assembly language output (actually a bunch of __asm__ directives for the C compiler to swallow) or C output. When the latter is used, additional flags must be passed to the compiler (-fdollars-in-identifiers) to get the output of munch to compile; otherwise the presence of $ in the symbols will cause the compile to fail. For this reason, the Tornado makefiles default to using the -asm option; the assembler has no problem with dollar signs.

The munched file, when compiled (by either method) containts two arrays of function pointers, _ctors and _dtors; these are a NULL-terminated list of the "constructor functions" and "destructor functions" (functions, one per file that has static ctors/dtors, which call all the static ctors/dtors in the file). This seems to work fine with the 2.7.2 toolchain. But with the 2.95.x toolchain; using the assembler rather than the compiler causes a subtle change in the symbol table entry for the _ctors and _dtors symbols (one that will NOT show up with nmppc; only objdumpppc -t reveals this). The "object" bit, which I suppose didn't exist with the 2.7 binutils; is NOT set when the input to the compiler is assembly code.

When the output of munch is linked back in with the module; everything is fine until you try loading it on the target. For some reason; loadLib DOES NOT RECOGNIZE _ctors and _dtors as valid symbols and thus does NOT load them into the symbol table. When cplusCtors is run (either manually, or automatically if cplusXtorSet is used); it looks in the symbol table to find _ctors; cannot find it; assumes that the module has no constructors, and silently exits. (The same applies for cplusDtors and _dtors).
The workaround is to add the line

MUNCH_FLAGS=
    

to your makefiles. This will force munch to output C code (which must be compiled with -fdollars-in-identifiers); which will have the "object" bit set in the generated object file. loadLib will then properly generate symbol table entries for _ctors and _dtors, and all will be well.

Again, this affects GCC 2.95.x (using DaveK's stuff) on PowerPC. Don't know about other architectures. The 2.7.2 toolchain that ships with Tornado also seems to be unaffected.
(From: sj@shell1.aracnet.com, Scott Johnson)


5.2 Communication problems

Q: Is there any instance where msgQDelete can be blocking?

A: Yes, as with a lot of create and delete functions in VxWorks, msgQDelete() will make use of the dynamic memory management software to release the memory that was claimed for the message queue data structures (both the kernel's object structure and the buffer for messages in this case).
Since access to memory partitions is guarded by a mutex (a good idea!), it is certainly possible that any xxxCreate or xxxDelete routine could block. You shouldn't be using these functions in high performance blocks of code - it is generally best to keep your create and delete operations to initialisation/shutdown regions of the code.
Now, in the case of message queues, an additional step is performed: the delete function makes sure that it 'holds' all the message slots so if there are any messages already in the queue they will still be delivered (and your task that is trying to delete the message queue will block until they are). For most people, that is the desirable behaviour since it makes sure that no messages are lost...
(From: john_94501@my-deja.com)


5.3 Interrupts

Q: In my BSP there is an intConnect, but no intDisconnect. How can I disconnect a function from a interrupt?

A: I have attached an "intDisconnect()" routine for PPC that has served me well for many years. Just include it as an extra object when you are compiling your kernel. It takes one argument (the interrupt vector).

intdisc.c

(From: David Abbott, abbottd@jlab.org)


Q: What does "workQPanic: Kernel work queue overflow" mean?

A: It usually means that one of your Interrupt Service Routines is not clearing the IRQ status properly, so on exiting the ISR the interrupt line is still active and it is just called again immediately. If you can't work out which it might help to try and get a logic analyser to look at the interrupts that are occurring.
(From: Andrew Johnson, anj@aps.anl.gov)


Q: What does the function "__get_eh_context" do?

A: "__get_eh_context" is an abbreviation for "get exception handler context". This will be called if you have C++ code, you are executing in an objects context and you have exception handling enabled. The code uses the `this' pointer and can setup RTTI (run time type identification) and other C++ facilities.
You could use only Embedded C++ constructs and you will probably be ok. Alternatively, don't allocate any objects, even on the stack in your ISR. Object construction can call malloc and other routines that you shouldn't use. It will definitely setup an exception context so that if an exception is thrown, the object can be deleted.
(From: Bill Pringlemeir, spam_account@sympatico.ca)

C++ can be used in ISRs with extreme caution, like having the ISR in a separate module that you can build using -fno-exceptions and -fno-rtti and being careful not to construct any objects and watching out for temporaries caused by reference parameters and so on, but there are so many pitfalls that my advice would be to always write such lowlevel code as ISRs and even the lower layers of device drivers in plain C.
(From: Dave Korn)


Q: After calling intlock it seems that the interrupts are not locked when looking at the interrupt control register.

A: Seems that people still do not understand the scope of intLock(). It works only for the task context that calls it. If that task blocks (or exits), then interrupts will most probably be re-enabled. If the task only blocked, when it resumes execution they will be locked again.
Why? Because the MSR (using PPC) is in the task context. You should not block with interrupts locked (or, for that matter, after calling taskLock() either). Switching to a different task, or the idle loop, will re-enable the interrupts.
As for the wind shell (host shell), when you execute a command there, the target agent spawns a task to call the function. So calling intLock() from the wind shell results in a task on the target executing intLock() and exiting. When the task exits, the scheduler will be invoked and when the new task is selected, its value for the MSR will be restored.
(From: John, john_94501@yahoo.com)
(Note: this is also the case on MIPS. Also when calling intEnable on MIPS the interrupt will only be enabled for the task where you called intEnable; Johan)


5.4 LoadModule problems

Q: When I try to load a module with unresolved externals the function loadModule returns a module-ID instead of returning NULL, as described in the manual. How do I detect if there are unresolved externals?

A: First set errno to 0, then execute the call to loadModule, and if this call returns a valid module-ID check errno again. If errno indicates an error there probably were some unresolved externals. In this case it is better to unload the module again.
(From : Bob Marino, ram@mr.picker.com)


Q: The ld command, run from a script, is behaving differently on a UNIX and an NT box.

A: I've observed a difference with the behavior of startup scripts. The ld command's normal form:

  ld < foo
    

worked fine with a UNIX host, but failed on NT. I eventually found that the terminating >CR< was being included in the file name read from the script and passed back to the ftp server. The workaround was to use an alternate form of the ld command in startup scripts:

  ld 1,0,"foo"
    

This works fine with both UNIX and NT hosts.
(From: Jerry Hudgins, jerry@e-farm.com)


5.4A malloc and other memory issues

Note: this section is added later, but to keep the order right and not have to renumber all sections I added it as 4A.

See section 6.2 for information about memory leak detection

Q: The VxWorks port of an alternative code for dynamic memory allocation, made by Doug Lea.

A: This post provides details of getting Doug Lea's allocator (dlalloc) to work with vxWorks 5.4 (possibly 5.5).
See: "ftp://gee.cs.oswego.edu/pub/misc/malloc.c"
These posts are based on version 2.7.2 of the allocator. There are three files.

After extracting the memLib.o and memPartLib.o, these must be added to the build as extra object files. The file "malloc.mk" is never used again unless you wish to generate these files each time you build. Then you might insert the rules directly into your vxWorks makefile or project. The malloc.c files should be compiled and linked before any libraries.
This will enhance performance on system that make extensive use of C++ and objects.
(From: Bill Pringlemeir)


Q: One of my tasks in getting suspended all the time, in memPartFree. What is causing this?

A: In vxWorks land, freeing same memory location twice will suspend the task which has called free() second time. This will cause exception similar to one above suspending the task.
The way to fix this is by making sure you don't free memory twice.
(From: Narendra Hadke, narenh@intotoinc.com)


5.5 pthreads

Q: Has anyone ported pthreads.h from Linux to VxWorks?

A: Yeah, we've done that. The mapping from pthreads to VxWorks task_* et al. is pretty straightforward. The only thing missing is condition variables. They turned out to be kind of hard. You might also be able to use VxWorks semaphores, but we took a different approach. We used a msgQ and taskSuspend()/taskResume(). See this file for the implementation: pthreads.c
The rest of the implementation is very easy, so I won't bore you with the details.
(From: Craig Vanderborgh, craigv@voxware.com)


Q: Is there a way to implement the VxWorks API on top of pthreads, to simulate VxWorks on a different system?

A: Check out http://www.mvista.com - they've recently published a white paper that discusses this and the problems and differences between the two APIs.
(From: Andrew Johnson, anj@aps.anl.gov)


5.6 Reboot

Q: When I do a hard reboot the system reacts differently than when using Ctrl-X. The reason is that Ctrl-X does a reboot(0), while a hard reboot does a reboot(2), a boot clear. How can I let Ctrl-X do a reboot(2)?

A: Unfortunately, the ^x functionality is hardwired to do a "reboot (BOOT_WARM_AUTOBOOT)" call when the reboot character is recognized. There isn't any way to change what type of reboot is done. Some possible ways around this (none pretty) are to:

  1. Change the sysToMonitor function that gets called as the last step of a reboot to override the "start type" used. This function is normally provided in sysLib.c as part of your BSP.
  2. Use the abort function capability of the terminal driver to do the type of reboot you want. The abort function is normally tied to ^C and is used to restart the "shell". If you can live without that capability, you could use tyAbortSet() to change the abort character to ^X and use tyAbortFuncSet() to install a function that would do the proper type of reboot (i.e. call reboot(BOOT_COLD)). You would need to make sure OPT_ABORT option was enabled for the serial connection.
  3. Install your own "reboot" handler that "took over" and finished the reboot process. You could use rebootHookAdd() to put in a function that did what reboot does. As I remember from when I decoded the routine it did some cache disabling and then called sysToMonitor() with the "start type" parameter. You could do those same things with your functions; calling sysToMonitor(BOOT_COLD).

The first option is the easiest by far.
(From: Fred Roeber, froeber@bbn.com)


5.7 Semaphores

Q: It looks like the priority inversion mechanism is not working correctly.

A: This may not be the issue here, but you should note the throw-away line in the semMLib description:

"The task will return to its normal priority only after relinquishing all of its mutual-exclusion semaphores that have the inversion-safety option enabled".

So if your Task Two happens to have hold of some other (probably unrelated) inversion-safe mutex, this will prevent it from reverting to its former priority, even though Task One is not waiting on the semaphore you are currently focussing on. (This was the cause of a deadlock I recently encountered!)
(From: Will Fookes, will@noSpam.wfookes.co.uk)


5.8 Simulator (VxSim)

Q: How can I start multiple simulators on NT and have these communicating?

A: While in a VxWorks class, the instructor gave me the following info. With this I was able to finally get it to work!
Just two things:

  1. Make sure you configure WDB END driver instead of the WDB simulator pipe.
    development tool components -> WDB agent components ->
    select WDB connection -> WDB END driver connection
  2. I got an exception using buffers greater then 1400 with a TCP connection. Fragmentation problem? Same code works fine on real hardware.

The info in in this file.
(From: Luc Pariseau, lparisea@nortelnetworks.com)


Q: How do I increase the memory of the simulator?

A: Use the /r switch to control the amount of memory of the simulator. The size is in bytes, and not in kBytes as the manual states. You also have to build a custom-configured simulator, as the default simulator does not support the /r-switch.

In case the command line is not an option, here is another way: I think the magic line you want to change is in 01Simulator.win32.tcl: [::simulatorLaunch $imageName $pNo $workingDir 30000] \ and the 30000 will be your memory size. If you don't want to brute force it you can add code to the showImageDlg procedure (look at the dialog on the bottom of the file) to prompt you for it. Right now it seems as if it's hardcoded on win32 platform and they prompt you only on UNIX.. (look in the Launch directory for the UNIX implementation)
(From: Steven Szabo, Steven.Szabo@motorola.com)


Q: How can I have 2 simulators communicate with eachother on Win2K box?

A: You need to setup the ULIP driver correctly, which means you need to enable IP-Routing.
Here is the result of my "ipconfig /all" (Sorry, output is in German! (Ja means Yes, Nein means No)):

Windows 2000-IP-Konfiguration

        Hostname. . . . . . . . . . . . . : martin
        Primares DNS-Suffix . . . . . . . :
        Knotentyp . . . . . . . . . . . . : Hybridadapter
        IP-Routing aktiviert. . . . . . . : Ja
<-------------------
        WINS-Proxy aktiviert. . . . . . . : Nein

Ethernetadapter "vxSIM WindRiver":

        Verbindungsspezifisches DNS-Suffix:
        Beschreibung. . . . . . . . . . . : WindRiver ULIP
        Physikalische Adresse . . . . . . : 00-00-00-00-00-00
        DHCP-aktiviert. . . . . . . . . . : Nein
        IP-Adresse. . . . . . . . . . . . : 90.0.0.254
<--------------------
        Subnetzmaske. . . . . . . . . . . : 255.255.0.0
<-------------------
        Standardgateway . . . . . . . . . :
        DNS-Server. . . . . . . . . . . . :
    

Pinging from one to the other vxSim works fine. But you need to start the Simulator using a processor number >0, then you will get the target server calling parameters to start with wdbrpc: 90.0.0.2 -B wdbrpc -Bt 3 -R f:\TEMP\tsfs -RW -n "vxsim1@martin"

Here is my output:
Simulator #1 to #3:

-> ping "90.0.0.4"
PING 90.0.0.4: 56 data bytes
64 bytes from vxTarget (90.0.0.4): icmp_seq=0. time=0. ms
    

Simulator #3 to #1:

-> ping "90.0.0.2"
PING 90.0.0.2: 56 data bytes
64 bytes from vxTarget (90.0.0.2): icmp_seq=0. time=0. ms
    

Simulator #3 to win2k host:

-> ping "90.0.0.254"
PING 90.0.0.254: 56 data bytes
64 bytes from host (90.0.0.254): icmp_seq=0. time=0. ms
    

(From: Martin Raabe, Martin.Raabe@WindRiver.com)


Q: The font in my VxSim window is very small.

A: You are probably using Regional settings other than English. If you change it to English, it should work. There is also another way where you don't have to change regional settings and it involves tempering with the code of VxWorks.exe.
(From: Tomislav Razov, tomislav.razov@siemens.hr)

It is also possible to use the following tool. The exe file should be run after each time you run the simulator. We integrated the call into the resposible TCL file, which is attached also. The tool (source and executable) can be found here: SimFont.zip.
(From: Ofer Goren, ofer_goren@iamba.com)


Q: How can I make 2 simulators communicate on a Solaris box?

A: Enable IP forwarding on solaris.

ndd -set /dev/ip ip_forwarding 1
    

(From: Vijay Paul, paulv@lucent.com)


5.9 Task related items

Q: What is the use of taskDelay(0)?

A: The following msg was posted by Dave Schmidt of Wind River on the newsgroup concerning taskDelay (0):

That will put the current task at the end of the ready queue for the current priority. It will allow any other tasks on the ready queue of the same priority to be run (sort of round robin, if you issue taskDelay(0) for them also when you want to go to the next task), of course all higher priority tasks will run and intterrupt service routines will also run.
Please note that this method will NOT allow tasks of lower priority to run, it just forces a rescheduling. If the task being delayed is the only one of that priority, then it will restart immediately.


Q: How do I use taskInit?

A: First: why use taskInit? If you want to synchronise startup use taskInit and let the new task(s) wait on a semaphore.
But if you still want to use it, here are some examples:

From john_94501@my-deja.com:
This code is cut from something that uses taskInit in a portable way (i.e. it takes into account the stack direction of the CPU being used). This is another reason why I prefer to use taskSpawn!

    int ret;
    char    *memArea;

    /* initialize TCB and stack space */

    memArea = (char *) malloc (STACK_ROUND_UP(STACK_SIZE) + sizeof (WIND_TCB) + 16);

    /* initialize task */

    ret = taskInit ((WIND_TCB *) (memArea + 16), NULL, 150, VX_NO_STACK_FILL,
#if (_STACK_DIR == _STACK_GROWS_DOWN)
            (char *) (memArea + STACK_SIZE + sizeof (WIND_TCB)),
#else
            memArea + STACK_ROUND_UP (sizeof (WIND_TCB) + 16),
#endif
            STACK_SIZE, (FUNCPTR) function,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0);    /* args */

    if (ret == ERROR)
    {
        perror ("taskInit");
        return(0);
    }
    else
    {
        taskActivate ((int) memArea);
    }
    

And that is basically it! Your task should be running by the end of that sequence. If you wish to delay the starting point just move the call to taskActivate().

Another example from steven.offenbacher@jhuapl.edu:

I also have a working example where I don't use malloc. I statically create the TCB and stack.

    WIND_TCB tMonitorTcb;
    char tMonitorStack[STACK_SIZE];

    /*
     Example #04.  taskInit/taskActivate method using statically allocated
                   TCB and stack
     */
    status = taskInit(&tMonitorTcb,              /* TCB Address        */
                 "tMonitorMethod04",             /* Task/Thread Name   */
                 240,                            /* Priority 0=Highest */
                 VX_NO_STACK_FILL,               /* Options            */
                 /*
                  Determine which way stack grows and
                  adjust address if necessary
                  */
#if (_STACK_DIR == _STACK_GROWS_DOWN)
                 tMonitorStack+STACK_SIZE,       /* Stack base address */
#else
                 tMontiorStack,                  /* Stack base address */
#endif
                 STACK_SIZE,                     /* Stack size in bytes*/
                 (FUNCPTR) monitor,              /* Task entry point   */
                 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0);  /* VxW Req 10 parms   */

    /*
     Task exists but is not running at this point.  The debugger can now attach to the task
     and set breakpoints provided the user does not detach or attach to some other task
     */
    if (status == OK)                            /* Only activate if init ok */
        status = taskActivate((int)&tMonitorTcb);/* Actually start task */
    


Q: When the priority of a task is requested using taskPriorityGet it is possible that this is not the real value, as this might change due to priority inversion. How do I get the right value?

A: The normal priority is kept in the TCB. It can be read using this command:

priority = (taskTcb(taskIdSelf()))->priNormal;
    

(From cwein@my-deja.com and Pete Kockritz, pkockritz@home.com)


Q: Using WindView, I've noticed a task that has just completed (eg. by returning) doing the following in close sucession:

Why this order, the task would have been deleted after the first call to taskDelete anyway.

A: The sequence is not only familiar, but it is correct, at least as far as the deletion of the task... let me explain in more detail...
Normally, when one task deletes another the one doing the work has a context, stack etc to execute the task deletion code on. This is necessary, obviously, since the code performing the deletion is simply C code, and might block or be interrupted.
Now, when a task deletes itself it has a small problem: it can't delete its own stack and context information (TCB), since that would leave the executing code without any stack or context. OK, it could lock interrupts until it was all cleaned up, but that would not be good in a real time OS where interrupt latency is an important factor.
So, the taskDelete() code performs some checks up front, and if it is deleting itself the work is actually passed to another task to do (tExcTask in this case). The actual code is a little more involved, but this is a rough idea of what happens (function names not accurate, but chosen to express the concept):

if (taskToDelete == taskIdSelf()
    {
    queueJob (taskDelete, taskToDelete);
    taskSuspend (0);
    }
    

Since the exception task is a high priority task it will preempt the task deleting that was itself in most cases. At some point in the process, the taskDelete operation blocked for something. At that time, the original task was rescheduled, and promptly suspended itself (after all, it is expecting to die very soon...).
Your description sounds pretty much like what I'd expect WindView to see for a task deletion. The "exception" task is not really that well named since it is used for more than just displaying exception messages. Consider it to be a kernel thread, used for the OS to push work out to task level, much like an ISR that signals an associated task to perform the actual work.
(From: john_94501@my-deja.com)


Q: How can I build a stack-trace?

A: You can do this using an undocumented function called "trcStack". Here is all you need. You can even call xxxTrace(tid) from interrupt level... though logMsg() is far from ideal.

/*******************************************************************************
*
* xxxTracePrint - stack trace print function
*
* RETURNS: OK or ERROR
*/

static void xxxTracePrint
    (
    INSTR *caller,
    int func,
    int nargs,
    int *args
    )
    {
    char buf [250];
    int ix;
    int len = 0;

    len += sprintf (&buf [len], "%#10x: %#10x (", (int)caller, func);
    for (ix = 0; ix < nargs; ix++)
        {
        if (ix != 0)
            len += sprintf (&buf [len], ", ");
        len += sprintf (&buf [len], "%#x", args [ix]);
        }

    len += sprintf (&buf [len], ")\n");

    logMsg (buf);
    }

/*******************************************************************************
*
* xxxTrace - stack trace
*
* RETURNS: OK or ERROR
*/

int xxxTrace
    (
    WIND_TCB *pTcb
    )
    {
    REG_SET regs;

    if (pTcb == NULL)
        return (ERROR);

    taskRegsGet ((int)pTcb, &regs);
    trcStack (&regs, (FUNCPTR) xxxTracePrint, (int)pTcb);

    return (OK);
    }
    

(From: Geoffrey Espin, espin@idiom.com)


Q: What is the syntax of "taskSpawn" for spawning a method of an object (C++) as a task.

A: I use the following code snippets to spawn a method as a task. Dont forget the '(int)this' for the first parameter.

//start sampling data count and timestamp
timeCodeGather = true;
tid = taskSpawn("tTimestamp", 250, 0, 20000,
                                (FUNCPTR)TimeStamp::addNewTimeStamp,
                                (int)this, 0, 0, 0, 0, 0, 0, 0, 0, 0);




void TimeStamp::stopTimeCodeGatheringTask()
{
//## begin TimeStamp::stopTimeCodeGatheringTask%1945920847.body preserve=yes
        int rd;
        char tmpbuf[20];

        if (timeCodeGather)
        {
                //stop timecode gathering task
                taskDelete(tid);
........
    

From: Bob, Bob@dskti.com)


Q: How can I detect a stack overflow?

A: In the past I used the next code (typically for x86 targets):

int switchHandler(WIND_TCB *pOldTcb, WIND_TCB *pNewTcb)
{
        if ((pOldTcb->regs.esp < (ULONG)pOldTcb->pStackLimit) ||
            (!(pOldTcb->options & VX_NO_STACK_FILL) &&
             ((int)*(int *)(pOldTcb->pStackLimit) != 0xeeeeeeee)))
        {
                logMsg("Stack overflow task 0x%08x\n", (int)pOldTcb,0,0,0,0,0);
                taskSuspend((int)pOldTcb);
                /* __asm__("int $12"); */
        }
        return 0;
}

int start_application(void)
{
    /* Enable kind of dynamic stack checking */

    if (taskSwitchHookAdd(switchHandler) == ERROR)
    {
            printf("taskSwitchHookAdd error\n");
            return ERROR;
    }
    ...
}
    

(From: Gerald van Kampen, kam@oce.nl)


Q: I want to block a task until all children are in a certain state (initialised, finished, etc.).

A: This can be done using semaphores:

/*
 * Global semaphore used by each terminating child CSP task.
 */
SEM_ID childFinished;

/*
 * A child task.
 */

void child (void)
{
    /* Normal child like activities. */

    semGive (childFinished);
}

#define  NUM_CHILDREN  5

/*
 * Parent task.
 */
void parent (void)
{
    int childCount = 0;

    /*
     * Use a FIFO if you are more interested in speed than the order that
     * tasks will be blocked in.
     */
    if ((childFinished = semCCreate (SEM_Q_FIFO, NUM_CHILDREN)) == NULL)
    {   /* We're not in the mood for creating children :-( */
        return;
    }

    /* Spawn children, the fun part ;-) */

    do
    {   /* Wait for all the children to complete their chores */
        semTake (childFinished, WAIT_FOREVER);
    } while (++childCount < NUM_CHILDREN);

    /* Tidy up after children (usual parental type stuff) */
    semDelete (childFinshed);
}
    

(From: Alex Goodyear, spamless.agood@jet.uk)


Q: What are +T, +I thingies in the "i" output?

The following is an excellent description of all these symbols by many people on the net, including "Fred J. Roeber" and others:

      Description                                 Status symbol
      =====================================       ===============
       and task's priority inherited          + I                    
      Delayed and suspended                        DELAY+S
      Pended and suspended                         PEND+S
      Pended and Delayed                           PEND+T
      Pended, delayed and suspended                PEND+S+T
      

The DELAY state indicates that the task has done some sort of delayed call while PEND means the task has done something that caused it to block like trying to semTake a semaphore someone else was holding. PEND+T means that the task is both delaying and pending; it has done a semTake with a timeout. +I means that the task has (temporarily) inherited a higher priority through the use of a mutex semaphore.
The priority inheritance protocol also accounts for the ownership of more than one mutual exclusion semaphore at a given time. A task in such a situation will execute at the priority of the highest priority task blocked on any of the owned resources. The task will return to its normal, or standard, priority only after relinquishing all of the mutual exclusion semaphores with the inversion safety option enabled.
If you use nested mutex semaphores with priority inheritance turned on then when a task inherits a high priority due to some inner semaphore it owns, it doesn't lose that priority until it relinquishes all the semaphores it holds. This doesn't quite follow the rules for priority inheritance (to the extent that there really are any rules) in that normally, a task's inherited priority should decrease as it releases each nested semaphore to whatever the priority ceiling is for the semaphores it still holds. Getting this incremental priority reduction to work right in practice, though, is extremely difficult (some of the SUN papers on the Solaris real time scheduling indicate that this was one of the hardest things for SUN to get right in their OS upgrades). Given that VxWorks is a real time embedded OS, I, for one, don't care if WRS uses the current implementation even though it isn't "pure" because the result is a more reliable implementation that runs more deterministically. Anyway, my guess is that you will find that you have some nested semaphore code where you are doing something after releasing one of the nested semaphores that shouldn't be done at a high priority.
(From the old FAQ)


5.10 Time related items

Q: I would like to know how to measure the system time at a specific moment, then at another moment, only a few milliseconds later, to determine elapsed time.
I have tried clock_gettime(), but this is no good. I have checked the clock resolution and it is at 60 ticks per second.

A: The following was written by Fred Roeber (froeber@bbn.com) in the newsgroup:

The easiest/best way to measure detailed elapsed time is to use any "timestamp" driver that may be supplied as part of your board's BSP. The timestamp driver is a generic name for a high resolution timing factility that is intended for WindView use but can also be used by user applications. The documentation for creating/using the timestamp facility is in Appendix G of the WindView manual and the functions are defined in h/drv/timer/timerDev.h (see sysTimestamp...).

Many BSPs come with timestamp driver support even if you don't buy WindView. You can add the configuration option INCLUDE_TIMESTAMP to build it into your system. You can then call sysTimestampEnable to start it up and sysTimestampLock to read detailed time values. You can call sysTimestampPeriod to find out how often the timer rolls over and sysTimestampFreq to see the rate it ticks at (which is often fast enough to provide microsecond resolution).

The reason I prefer this approach to cranking up the clock rate is that you typically get much higher resolution values without bogging down the system with all the overhead of frequent timer interrupts.

As with most things in VxWorks, caveats are needed in applying a generic facility to specific boards. First, not all boards have timestamp driver support. Second, on those that do, the timestamp sometimes has a pretty small period (it rolls over frequently). For instance, on the PPC platform, the "standard" timestamp driver derives the timestamps from the decrementer timer which is also used for the system clock. This means the time value rolls over at the rate the system clock rate; making it pretty useless for measuring things with a long duration.

There is an alternative timer for some PPC boards that uses the Z8536 chip. The other day, we needed to time startup code on our Radstone PPC board and I found that with a little work the PPC timestamp functions fit the bill nicely. The ppcZ8536Timer.c can be rewritten such that it only provides auxilliary clock and timestamp support (with no system clock support - that comes from ppcDecTimer.c). By using the 16 bit timers 1 and 2 in "linked" mode it was possible to get a nice 32 bit timer that rolled over every 20 minutes in our case. We left timer 3 on the chip for auxilliary clock support. The original timestamp functionality in the driver was, unfortunately, fairly well broken but not unsalvageable. Just trying to point out that in some (all?) cases you have to be careful when using VxWorks drivers.

Caveats aside, people should really consider the timestamp routines. They can often provide good timing insight with minimum trouble. Fred


Q: When I create a timer function my program crashes after the time specified instead of executing the function I specified. What is happening?

A: One thing to watch out for (it got me) is that your handler for the timer is executed IN THE CONTEXT OF THE TASK THAT CREATED IT. If the timer was created by some startup task which has since died and gone away, then this will quite likely crash your system the first time that the timer callback function is activated!
(From: Will Fookes, will@noSpam.wfookes.co.uk)


Q: How do I determine the number of ticks remaining in a watchdog timer?

A: I got this code from my FAE a few years ago. You will have to search for what you need to include for the state #defines and the OBJ_VERIFY() macro.

typedef struct
{
  int Ticks;
  int State;  /* OUT_OF_Q, IN_Q, DEAD */
} WD_INFO, *pWD_INFO;

STATUS wdGetInfo ( WDOG_ID wdId, pWD_INFO wdInf )
{
  FAST int    lock    = 0;
  int         ticks   = 0;
  int         state   = 0;

  /* LOCK INTERRUPTS */
  lock = intLock ();

  /*Verify watchdog ID */
  if (OBJ_VERIFY (wdId, wdClassId) != OK)
  {
    /* UNLOCK INTERRUPTS */
    intUNLOCK (lock);
    return ERROR;
  }

  /* record state */
  state = (int) wdId->status;

  /*If not in queue then ticks are zero*/
  if (state == WDOG_IN_Q)
  {
    ticks = Q_KEY (&tickQHead, &wdId->tickNode, 1);
    //ticks = 0;
  }
  else
  {
    ticks = 0;
  }

  /* UNLOCK INTERRUPTS */
  intUNLOCK (lock);

  /* fill structure */
  wdInf->Ticks = ticks;
  wdInf->State = state & 0x3;

  return OK;
}
    

(From: Bruce, intmainNOinSPAM@yahoo.com.invalid)


Q: Errors in the time modules.

A: taskDelay(-1) shows another bug in the vxWorks timer/tick code. It has the (side) effect of setting vxTicks to zero. This corrupts the localtime (and probably other things).
In fact taskDelay(x) will have the same effect if vxTicks + x >= 0x100000000.
If the system clock rate is 100Hz this happens after about 500 days (because vxTicks wraps). At faster clock rates it will happen sooner. Anyone trying for several years uptime?

Oh there is an undocumented upper limit on the clock rate. At rates above 4294 select() will fail to convert its 'usec' time into the correct number of ticks.
(From: David Laight, dsl@tadpole.co.uk)


Q: How can I create a repeat with a small delay without using busy-waiting?

A: The reason for not using busy-waiting is to allow other tasks to make use of the spare CPU cycles. But you must remember that context switching is quite a slow operation. Two task-swaps every 20usec for 1ms.means 100 task swaps per millisecond which works out equivalent to a task-switching tick rate of 100 kHz. Which would undoubtedly bog down the CPU pretty badly, and so not produce the desired saving, to put it mildly...
The 'correct' way to achieve this goal is to use an interrupt driven off a hardware timer. Do it something like this:

This solution then has the advantage that a) the 20usec. intervals are accurately timed by hardware rather than approximated by delay loops that will themselves be subject to interrupts and b) any spare CPU cycles are given to another task, but the task that has called into the driver only gets put to sleep once and woken up once.
Note that as described above, there will be a wasted 20usec delay at the start while waiting for the timer to first count down. You could perhaps do the first time from the foreground driver code at the same time as you set the timer going. Perfection is left as an exercise for the reader :-)
(From: Dave Korn)


Q: How can I monitor the processor-load?

A: The code we use for CPU monitoring is here - I've probably missed the odd definition from earlier in the file but I think they should be pretty self-explanatory. It creates a task at priority 255 = idle task level, which eats CPU and times itself. The routine getCpu() returns a doube which is CPU loading as a %. You have to run the initialise function at a high priority so it gets its autocalibration done properly.
(From: Andrew Johnson, anj@aps.anl.gov)

Another example.
Based on a discussion about this subject that I read here a few weeks ago, I wrote this idle time monitor that I have been testing. It seems to work very well.
You can add it to you build, then start it with nothing running

-> startCPUIdleMonitor
    

then spawn the task that prints the CPU Idle Time

-> period 10, getCPUIdlefloat
    

You will need to adjust the ZERO_LOAD_IDLE_COUNTER for your CPU. For my 50Mhz 860T it is around 377000
(From: RonnoBonno, RHNAssociates@yahoo.com)


Q: Can you give an example on how to use timers?

A: Take a look at this code. It should work without modifications.
(From: Michel Hendriks, m.hendriksNOSPAM@pijnenburg.nl)


Q: I noticed a rollover in the SNMP variable sysUpTime after around 2,5 days.

A: This can be fixed by editing snmpSystem.h which is supplied as source with WindNet, and calculating sysUpTime yourself rather than relying on the value from m2SysGroupInfoGet().
(From: Will Fookes, will@noSpam.wfookes.co.uk)


Q: When a timer expires, the connected routine will execute in which task context ?

A: The POSIX timer will execute in task context, same task that created the timer using POSIX signal mechanism, and you can taskLock() from within.
In contrast Wind WatchDog (wdLib) will do a similar service, but mor elight-weight, and will call the handler routing in interrupt context.
(From: Leonid Rosenboim)


Q: What is the difference between the watchdog library of VxWorks and the Posix watchdog mechanism?

A: The VxWorks watchdog (wdLib) is a software mechanism for many software modules to share a single hardware timer, that is the system clock. Each wdLib client can request a timeout which is a multiple of the system clock tick, and a user defined function (aka callback) is executed within interrupt service routine of the system clock interrupt.

Being run at ISR, the wdLib delivery callback is very accurate, as it is not subject to task priority, but the code therein should be kept as short as possibly, and comply with the limitations of an ISR, i.e. call only those system functions which are allowed for ISR, and avoid using floating point arithmetics.

The POSIX timer is an entirely different software mechanism, which uses the same system clock as its time reference, but uses the POSIX signal mechanism (versus callback) to deliver the timer alert to the requesting task, as a result, the signal function which is executed as a result of the timer expiration runs within the context of the task that requested the timer originally.

The signal delivery mechanism will be invoked effectively when the receiving task is scheduled, which is subject to that task's priority, so the delivery will be less accurate, and suffer greater delay, but is not limitted with respect to the length or complexity of code that can be executed therein. It will only effect the task which is associated with that timer.
(From: Leonid Rosenboim)


Q: How do I connect a callback to the SNTP server?

A: When starting up, run sntpsConfig, this will connect the sntpsClockHook function.

STATUS sntpsClockHook(int request, void *buffer)
  {
  struct timespec timeval;
  long value;
  ULONG *pTime;

  if (request == SNTPS_ID)
      {
      strcpy ((char *)buffer, "pps");
      return (OK);
      }

  if (request == SNTPS_RESOLUTION)
      {
      if (clock_getres (CLOCK_REALTIME, &timeval) == -1)
          return (ERROR);

      value = timeval.tv_nsec;
      *((ULONG *)buffer) = (ULONG)value;
      }

  if (request == SNTPS_TIME)
      {
      if (clock_gettime (CLOCK_REALTIME, &timeval) == -1)
          return (ERROR);
      pTime = (ULONG *)buffer;

      /* Copy number of seconds since 1900 to timestamp. */
      *pTime++ = timeval.tv_sec + SNTP_UNIX_OFFSET;

      /* Convert nanoseconds to fractional part and copy to timestamp */
      *pTime = sntpsNsecToFraction (timeval.tv_nsec);
      }

  return (OK);
  }


STATUS sntpsConfig (void)
  {
  if (sntpsClockSet ((FUNCPTR)sntpsClockHook) != OK)
    return(ERROR);

  return(OK);
  }
(From: Jimbob, jamesmh@excite.com)


5.11 Wind Web Server related items

Q: When I load a page from this server it takes a lot of time to load all the items on this page. How can I increase the speed?

A: Use more than 1 HTTP deamon for multiple HTTP request. You were overloading your HTTP deamon before.

#define HTTP_NR_OF_TASKS          1

Change this macro in your httpconf.c file.
(From: Computer Engineer, engineer4computer@netscape.net)


Q: A page loads good with Netscape, but IE seems to hang on an applet. When downloading using a different server everything goes OK.

A: Actually it is the same solution as on the previous question. The problem is, that IE loads the applets with another socket connection simultaneously to the rest of the page and since the WindWebServer is by default single tasked, it locks up. Setting

#define HTTP_NR_OF_TASKS          2

and the applets load on IE and NS as well.
(From: Andreas Vorgeitz, Andreas.Vorgeitz@de.bosch.com)


5.12 Zinc/windML related items

Q: How can I get the current cursor position?

A: The basic idea is to create input queues and attach them to the device. Then check the queue for a combination of conditions to see if the mouse has moved.

  1. Create Input Driver for mouse using either:

    Here you will specify the queue and interrupt number related to the mouse and also port address.

  2. call uglInputQEventGet to check for any new events...this can be in a low priority task. The elements in the queue will be in a structure of type UGL_INPUT_EVENT. You need to extract the x,y and 'id' from it.

More details with examples are in the Zinc manual.
(From: Vijay Kumar Peshkar, vpeshkar@cisco.com)


Q: Are there any alternatives to Zinc?

A: There were several discussion a few months back about this. You could try "groups.google.com" to look for them. Here are some links,

If you want a small gui that works out of the box with vxWorks, then you can code with WindML itself. This use to be called UGL. It is certainly capable of making a useful small screen GUI. Many features of Zinc really aren't needed for many products IMHO. Zinc is nice in allowing GUI development natively on a workstation or PC.
WindML is your best choice if you don't wish to port things. Microwindows might be a good choice if you have the time to port things.
(From: Bill Pringlemeir, spam_account@sympatico.ca)


Q: How can I avoid that a combobox blocks input to a editbox?

A: If keyboardGrabId is NULL, then use the winRootGet() member to send the keys to. While using Zinc 6.0, a combobox on the screen would cause edit boxes to stop receiving keyboard input.
Using the following patch will solve this.
In WindML 2.0 $(WIND_BASE)/src/ugl/win/winroute.c,

[start patch]
--- winroute2.c Wed Aug 15 14:16:12 2001
+++ winroute.c  Wed Aug 15 14:15:51 2001
@@ -137,6 +137,9 @@
             {
             UGL_WINDOW_ID keyboardGrabId = winKeyboardGrabGet (eventRouterId);

+            if (keyboardGrabId == UGL_NULL_ID)
+                keyboardGrabId = winRootGet (eventRouterId);
+
             if (keyboardGrabId != UGL_NULL_ID)
                 {
                 pInputEvent->header.objectId = keyboardGrabId;
[end patch]
    

(From: Bill Pringlemeir, spam_account@sympatico.ca)


Q: How can I save and restore the contents of the screen?

A: This works for me [change SCREEN_BASE define to match your video memory],

#include <VxWorks.h>
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>

#define SCREEN_BASE 0xc0000000
#define WIDTH 640
#define HEIGHT 480

void screenDump(unsigned char *name)
{
    FILE *fp;

    if(name == NULL || name[0] == 0)
        name = "screen.out";

    fp = fopen(name,"w+");
    fwrite((char*)SCREEN_BASE, sizeof(char),WIDTH*HEIGHT*4,fp);
    fclose(fp);
}
void screenPump(unsigned char *name)
{
    FILE *fp;

    if(name == NULL || name[0] == 0)
        name = "screen.out";

    fp = fopen(name,"r");
    fread((char*)SCREEN_BASE, sizeof(char),WIDTH*HEIGHT*4,fp);
    fclose(fp);
}
    

I call these from the shell.
(From: Bill Pringlemeir, spam_account@sympatico.ca)


Q: How can I use a telephone-like keypad to enter alphanumerics?

A: For the most part WRS/Zinc seem to assume an `embedded PC' with 101 keyboard, mouse and VGA.
I had the same problem and concluded that the Zinc layer was the best place to do this. I have some experience with hand helds, PDA and have used different cell phones. The best way is to enable the `key value' cycling when you are in the ZafFormatString class/gui element. The format string specifies whether the keyboard entry is going to be numeric, alpha, alphanumeric, etc. I have modified the file "src/zinc/generic/i_fmtstr.cpp"; specifically the Event() functions (especially E_KEY case (i hope you guessed that)).

    case E_KEY:
    {
        static const char special[30] =
        {
            '$', '%', '.', ',', '?', '!',  
            '+', '-', '*', '=', '^', '#', 
    

[snip, pressing zero several times allows punctuation.]

        static const char decode[10][8] = {
            {'0', ' ', '~'},
            {'1', 'q', 'z', 'Q', 'Z'},
            {'2', 'a', 'b', 'c', 'A', 'B', 'C'},
    

[snip, describes cycling sequence]

        // Search for legal characters.
        ZafIChar tChar = event.key.value;
        bool stepForward = true;           /* move cursor forward */

        // If special key, overwrite previous value (space).
        if('~' == lastKeyValue)
        {
            for(int i = 0; i < sizeof(special); i++)
    

[snip]

        // Check to see if we should not repeat a value.
        if(tChar != lastKeyValue)
        {
            if(D_ON == zKeyTimer->Event(ZafEventStruct(D_STATE)))
            {
                zKeyTimer->Event(ZafEventStruct(D_OFF));
                MoveCursor(L_RIGHT);
    

[snip...
OK, this is somewhat ugly. I did this under time pressure as always. Run through the `decode' array and look for two possible characters from IsLegalChar() virtual (or callback) function. If two are found and then we cycle through the values. Don't move the cursor forward and set a timer to move the cursor when that happens... ]

        // Cycle through keys.
        if(tChar >= '0' && tChar <= '9')
        {
            const char *p = &decode[tChar - '0'][0];
            int i = curKeyIndex;

            do
            {
                if(IsLegalChar(p[i], cursor))
                {
                    tChar = p[i];

                    // multiple key values for this key?
                    for(int j = i + 1; i != j; j = (j+1) %8)
                    {
                        if(IsLegalChar(p[j], cursor))
                        {
                            stepForward = false;
                            curKeyIndex = j;
                            lastCursor = cursor;
                            break;
                        }
                    }
                    break;
                }
                i = (i+1) % 8;
            } while(i != curKeyIndex);
        }

        if(tChar == '~')
        {
    

[snip, if zero is pressed several times bring up the ZafStringEditor class. I have totatlly re-written this as well...]

            ZafStringEditor *stringEditor = new ZafStringEditor;
            stringEditor->SetRequestor(this);
        }
        else if (IsLegalChar(tChar, cursor))
        {
            ZafEventStruct tEvent = event;
            tEvent.key.value = tChar;

            ZafUpdateType updateType = stringData->Update();
            stringData->SetUpdate(ZAF_UPDATE_NONE);
            stringData->Replace(cursor, 1, &tChar, 1);
            stringData->SetUpdate(updateType);

    

[only move forward if this is no possible cycling...]

            if(stepForward)
            {
                MoveCursor(L_RIGHT);

                // Reset cycle code. 
                lastKeyValue = 0;
                curKeyIndex = 0;
            }
            else
            {
                // Restart timer...
                zKeyTimer->Event(ZafEventStruct(D_INITIALIZE));
                zKeyTimer->Event(ZafEventStruct(D_ON));
            }
    

[...]
You must modify this for your application. I suggest that you get together with someone who knows your market and customize the UI to best fit your customers needs. This could be a key (*bad pun*) part of the product. Depending on your market, you may need some characters like "accente` gui`" [excuse my French] or other odd characters.
One strength of Zinc is that you can over-ride the behaviour of a class to fit your UI requirements; especially over plan vanilla WindML. A weakness is the resource overhead.
(From: Bill Pringlemeir, spam_account@sympatico.ca)


OpenGL programs running under VxWorks

I've written a layer between UGL/WindML and Mesa so now one can run OpenGL applications on VxWorks 5.4/UGL 2.0. This layer opens the doors of the embedded systems space to 3D graphics.
I've been inspired by xmesa sources thus I've used a similar design I've also ported some demos to WindML from GLUT for testing.
Wind River Systems gave his consent to release my work under MIT License. Thus many students and companies will be able to use Mesa on VxWorks.
The code is available for download from: http://sourceforge.net/projects/mesa3d
(From: Stephane Raimbault, stephane.raimbault@deesse.univ-lemans.fr)


5.13 Other items

Q: How can I decode the error numbers?

A: VxWorks errnos are divided into two parts. The high 16 bits specify a module number in which the error occurred, and the low 16 bits contain the module-specific error code.
To identify the module, look in $WIND_BASE/target/h/vwModNum.h. The beginning of the list looks like this:

/* module numbers - DO NOT CHANGE NUMBERS! Add or delete only! */
#define M_errno     (0 << 16) /* THIS MUST BE ZERO! */
#define M_kernel    (1 << 16)
#define M_taskLib   (3 << 16)
#define M_dbgLib    (4 << 16)
    

So for example if the errno is 0x320001, we look for module 50 (0x32 = 50) and find:

#define M_hostLib  (50 << 16)
    

So the error occurred in hostLib. The header file for hostLib is of course hostLib.h, so we look there for the hostLib-specific error codes, and find:

/* status messages */

#define S_hostLib_UNKNOWN_HOST   (M_hostLib | 1)
    

So error code 0x320001 is an Unknown Host error from hostLib!
(From: Dave Korn)


Q: How can I have a task that causes an (bus)error to continue after this occurs?

A: Take a look at this demo-code: sigVecDemo.c.
(From: Albert H Chen, albertchen@directvinternet.com)


Q: How can I use compression in my application?

A: You can use the inflateLib as it is provided with VxWorks. Another possibility is to use zLib. Get the source from http://www.gzip.org/zlib/ or http://www.info-zip.org/pub/infozip/zlib/. It should compile easily for vxWorks. This package is more flexible as you can handle gzip files.

# makefile.
CPU             = ?? Your CPU ??
TOOL            = gnu
EXTRA_DEFINE    = -Wcomment
MKDIR = mkdir
TGT_DIR = $(WIND_BASE)/target

OBJS=   adler32.o compress.o crc32.o deflate.o gzio.o infblock.o infcodes.o \
        inffast.o inflate.o inftrees.o infutil.o trees.o uncompr.o zutil.o

all : ($OBJS)

include $(TGT_DIR)/h/make/defs.bsp
include $(TGT_DIR)/h/make/make.$(CPU)$(TOOL)
include $(TGT_DIR)/h/make/defs.$(WIND_HOST_TYPE)

## Allow C++ sytle comments (tell Pre-processor).
ADDED_CFLAGS += -Wp,-lang-c
ADDED_CFLAGS += -DVXWORKS=1
ADDED_CFLAGS += -Wall -Winline -O2 -fomit-frame-pointer -fno-strength-reduce
ADDED_CFLAGS += -DNO_DEFLATE=1
    

The functions in gzio.o are nice. I don't think you have to modify any of the source.
(From: Bill Pringlemeir, spam_account@sympatico.ca)

I wrote a routine to uncompress an image compressed by deflate. The trick is that you have to skip the first byte. I think it's a 0x08; it's a tag that WRS adds to the start of the compressed block. Other than that it was just a matter of using the zlib routines to decompress it.
I haven't tried to compress an image with anything other than deflate, but it shouldn't be too hard.
I bet if you asked your FAE nicely, he'd get you the source to deflate and inflateLib.
(From: pkockritz@mac.com, Pete Kockritz)


Q: How can I autostart a loaded module.

A: without changing loader code or implementing an own version of loader: If you set C++ Constructor to automatic in VxWorks (standard), you might wrap your application by a static 'startup' class. The creator of the class may spawn the main task of your application.
(From: Michael Lawnick, Lawnick@softec.de)


Q: How can I check if the memory heap is corrupted?

A: Last week I was hunting down a nasty bug in our software. I finally found it using a self written function that checks the VxWorks memory list for errors.
The code is tested on a PPC 750 system, but should work on all systems.
These are the files:

(From: _remove_rene.straub@yetnet.ch, Rene Straub)


Q: How can I get the VxWorks and kernel version?

A: Use something similar to whats in WRS's bootConfig.c

#include 
#include 
(maybe some others also needed ...)

printf ("    CPU: %s\n", sysModel());
printf ("VxWorks: %s\n", vxWorksVersion);
printf (" Kernel: %s\n", (char *)kernelVersion());
printf ("    BSP: " BSP_VERSION BSP_REV "\n");
printf ("  Creation date: %s, %s using GNU C %d.%d\n",
        __DATE__ , __TIME__ , __GNUC__, __GNUC_MINOR__ ); 
      From: Melvin Gardipee "mbgardipee"@.NO_SPAM_HERE.raytheon.com)
    


5.14 VxWorks AE questions

Q: How can I access a fixed address register from within a user level domain?

A: This would work if the code was located in the kernel domain, but would not be allowed from a user level domain. Probably the simplest way of getting this to work from user level is to create a small function in your kernel that does this, make it an entry point and call it from your application...
(From: John, john_94501@yahoo.com)


Q: How can I spawn an application domain task from a privileged domain?

A: Actually there is a mechanism for this, and better still there is an example of using it included on every VxWorks AE CD/installation. I know, because I wrote the VxWorks AE portions of it!
Take a look in target/src/demo/PD and you will find an implementation of Eliza. This will show you how to create a domain dynamically, attach it to some code (so you don't even need a loader), and then start a task running in that new domain.
The call that starts the task is pdRun(). To make it work, somthing must have registered an init routine for the domain. There are two ways of doing that:

  1. As in the example, call pdInitRtnSet(). Be careful here: the routine that you set must be visible in the new domain as well as the current one - the example uses a shared library for this reason.
  2. Have a function called pdMain() in a module that you load dynamically into the new domain. The loader will automatically register this function for you as the domain's init routine. I have used this to run a multi-process graphical environment under VxWorks AE (part of the usability tests that we carried out before release).

(From: John, john_94501@yahoo.com)


Index

5.1 A When I download some C++ code my target crashes, even when I don't start anything.
B What is the syntax of "taskSpawn" for spawning a method of an object (C++) as a task.
C How can I call a C++ function from within a C-file?
D What is the preferred extension for C++ files?
E Gotcha with C++ static constructors and GCC 2.95.x (PPC)
5.2 A Is there any instance where msgQDelete can be blocking?
5.3 A In my BSP there is an intConnect, but no intDisconnect. How can I disconnect a function from a interrupt?
B What does "workQPanic: Kernel work queue overflow" mean?
C What does the function "__get_eh_context" do?
D After calling intlock it seems that the interrupts are not locked when looking at the interrupt control register.
5.4 A When I try to load a module with unresolved externals the function loadModule returns a module-ID instead of returning NULL, as described in the manual. How do I detect if there are unresolved externals?
B The ld command, run from a script, is behaving differently on a UNIX and an NT box.
5.4A A The VxWorks port of an alternative code for dynamic memory allocation, made by Doug Lea.
B One of my tasks in getting suspended all the time, in memPartFree. What is causing this?
5.5 A Has anyone ported pthreads.h from Linux to VxWorks?
B Is there a way to implement the VxWorks API on top of pthreads?
5.6 A When I do a hard reboot the system reacts differently than when using Ctrl-X.
5.7 A It looks like the priority inversion mechanism is not working correctly.
5.8 A How can I start multiple simulators on NT and have these communicating?
B How do I increase the memory of the simulator?
C How can I have 2 simulators communicate with eachother on Win2K box?
D The font in my VxSim window is very small.
E How can I make 2 simulators communicate on a Solaris box?
5.9 A What is the use of taskDelay(0)?
B How do I use taskInit?
C How do I get the real priority of a task?
D Question about order of execution for a taskDelete(taskIdSelf).
E How can I build a stack-trace?
F What is the syntax of "taskSpawn" for spawning a method of an object (C++) as a task.
G How can I detect a stack overflow?
H I want to block a task until all children are in a certain state (initialised, finished, etc.).
I What are +T, +I thingies in the "i" output?
5.10 A I would like to know how to measure the system time at a specific moment, then at another moment, only a few milliseconds later, to determine elapsed time.
B When I create a timer function my program crashes after the time specified instead of executing the function I specified. What is happening?
C How do I determine the number of ticks remaining in a watchdog timer?
D Errors in the time modules.
E How can I create a repeat with a small delay without using busy-waiting?
F How can I monitor the processor-load?
G Can you give an example on how to use timers?
H Rollover in the SNMP variable sysUpTime after around 2,5 days.
I When a timer expires, the connected routine will execute in which task context?
J What is the difference between the watchdog library of VxWorks and the Posix watchdog mechanism?
K How do I connect a callback to the SNTP server?
5.11 A When I load a page from this server it takes a lot of time to load all the items on this page. How can I increase the speed?
B A page loads good with Netscape, but IE seems to hang on an applet.
5.12 A How can I get the current cursor position?
B Are there any alternatives to Zinc?
C How can I avoid that a combobox blocks input to a editbox?
D How can I save and restore the contents of the screen?
E How can I use a telephone-like keypad to enter alphanumerics?
F OpenGL programs running under VxWorks
5.13 A How can I decode the error numbers?
B How can I have a task that causes an (bus)error to continue after this occurs?
C How can I use compression in my application?
D How can I autostart a loaded module.
E How can I check if the memory heap is corrupted?
F How can I get the VxWorks and kernel version?
5.14 A [AE] How can I access a fixed address register from within a user level domain?
B [AE] How can I spawn an application domain task from a privileged domain?


VxWorks Homepage
© J.A. Borkhuis, 2000 - 2005
Send me an e-mail if this page was helpfull