Control a thread
#include <sys/neutrino.h> int ThreadCtl( int cmd, void * data ); int ThreadCtl_r( int cmd, void * data );
For more information, see below.
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
These kernel calls allow you to make QNX-specific changes to a thread.
The ThreadCtl() and ThreadCtl_r() functions are identical except in the way they indicate errors. See the Returns section for details.
The sections that follow describe the possible commands.
ThreadCtl(_NTO_TCTL_ALIGN_FAULT, data)
This command controls the response to a misaligned access. The data argument must be a pointer to an int whose value indicates how you want to respond:
The function sets data to a positive or negative number, indicating the previous state of the alignment-fault handling.
Threads created by the calling thread inherit the _NTO_TCTL_ALIGN_FAULT status. |
ThreadCtl(_NTO_TCTL_IO, 0)
Request I/O privileges; let the thread execute the in, ins, out, outs, cli, and sti I/O opcodes on architectures where it has the appropriate privilege, and let it attach IRQ handlers. If a thread attempts to use these opcodes without successfully executing this call, the thread faults with a SIGSEGV when the opcode is attempted.
|
ThreadCtl(_NTO_TCTL_NAME, data)
Set or retrieve the name of the current thread. The data argument must be a pointer to a _thread_name structure, which is defined as follows:
struct _thread_name { int new_name_len; int name_buf_len; char name_buf[1]; };
The name_buf member is a contiguous buffer that extends the structure; name_buf_len is the size of this buffer.
If new_name_len is: | The command: |
---|---|
Less than 0 | Copies the thread's current name into name_buf, up to the number of bytes specified by name_buf_len |
0 | Deletes the thread's name |
Greater than 0 | Sets the thread's name to the value in name_buf, up to the number of bytes specified by name_buf_len |
If you're setting or deleting the thread's name, the old name is copied as a NULL-terminated string into name_buf, up to the number of bytes specified by name_buf_len.
|
Here's an example:
#include <stdio.h> #include <sys/neutrino.h> #include <stdlib.h> int main () { struct _thread_name *tname; int size; size = sizeof(*tname) * 2 + _NTO_THREAD_NAME_MAX * sizeof(char); tname = malloc (size); if (tname == NULL) { perror ("malloc"); return EXIT_FAILURE; } else { memset (tname, 0x00, size); tname->name_buf_len = _NTO_THREAD_NAME_MAX; /* To change the name, put the name into name_buf and set new_name_len to the length of the new name. */ strcpy (tname->name_buf, "Hello!"); tname->new_name_len = strlen (tname->name_buf); if (ThreadCtl (_NTO_TCTL_NAME, tname) == -1) { perror ("ThreadCtl()"); return EXIT_FAILURE; } else { printf ("The old name was: '%s'.\n", tname->name_buf); } /* To get the current name, set new_name_len to -1. */ tname->new_name_len = -1; if (ThreadCtl (_NTO_TCTL_NAME, tname) == -1) { perror ("ThreadCtl()"); return EXIT_FAILURE; } else { printf ("The current name is: '%s'.\n", tname->name_buf); } /* To delete the name, set new_name_len to 0. */ tname->new_name_len = 0; if (ThreadCtl (_NTO_TCTL_NAME, tname) == -1) { perror ("ThreadCtl()"); return EXIT_FAILURE; } else { printf ("The old name was: '%s'.\n", tname->name_buf); } free (tname); } return EXIT_SUCCESS; }
ThreadCtl(_NTO_TCTL_ONE_THREAD_CONT, data)
Unfreeze the thread with the given thread ID, which was frozen by an earlier _NTO_TCTL_ONE_THREAD_HOLD command. The data is the thread ID, cast to be a pointer (i.e. (void *) tid). This command returns an error of ESRCH if there's no thread with an ID of tid.
This call was added in the QNX Neutrino Core OS 6.3.2. |
ThreadCtl(_NTO_TCTL_ONE_THREAD_HOLD, data)
Hold the thread with the given thread ID in the calling process. The data is the thread ID, cast to be a pointer (i.e. (void *) tid). This command returns an error of ESRCH if there's no thread with an ID of tid.
This call was added in the QNX Neutrino Core OS 6.3.2. |
ThreadCtl(_NTO_TCTL_RUNMASK, data)
Set the processor affinity for the calling thread in a multiprocessor system. The data is the runmask, cast to be a pointer (i.e. (void *) runmask). Each set bit in runmask represents a processor that the thread can run on.
By default, a thread's runmask is set to all ones, which allows it to run on any available processor. A value of 0x01 would, for example, force the thread to run only on the first processor.
You can use _NTO_TCTL_RUNMASK to optimize the runtime performance of your system by, for example, relegating nonrealtime threads to a specific processor. In general, this shouldn't be necessary, since the Neutrino realtime scheduler always preempts a lower-priority thread immediately when a higher priority thread becomes ready.
The main effect of processor locking is the effectiveness of the CPU cache, since threads can be prevented from migrating.
Threads created by the calling thread don't inherit the specified runmask. |
ThreadCtl(_NTO_TCTL_RUNMASK_GET_AND_SET, data)
Get and set the runmask (the processor affinity) to a proper value for the calling thread in a multiprocessor system. The data parameter is a pointer to the runmask. On input, the pointer to value is used to set the new runmask for the thread (see _NTO_TCTL_SET_RUNMASK for details). After the function has completed, the contents of *data will be replaced with the previous runmask for the thread. Calling ThreadCtl again with the same pointer will restore the runmask to the state before the call.
ThreadCtl(_NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT, data)
Manipulate the calling thread's runmask and inherit mask. The data argument must be a pointer to a struct _thread_runmask. Conceptually, this structure consists of these members:
However, the size of the masks (and hence the size of the structure) depends on the number of processors on your system. We've defined the following macros to make it easier for you to work with this structure:
The _NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT command saves the values for both masks at the time of the call in their respective members of this structure. If you pass 0 for the masks, the masks are left unaltered; otherwise they're set to the specified value(s).
This call was added in the QNX Neutrino Core OS 6.3.2. |
Here's an example:
#include <sys/neutrino.h> #include <sys/syspage.h> #include <malloc.h> #include <stdio.h> int main(void) { int *rsizep, rsize, size_tot; unsigned *rmaskp, *inheritp; unsigned buf[8]; void *freep; /* * struct _thread_runmask is not * uniquely sized, so we construct * our own. */ rsize = RMSK_SIZE(_syspage_ptr->num_cpu); size_tot = sizeof(*rsizep); size_tot += sizeof(*rmaskp) * rsize; size_tot += sizeof(*inheritp) * rsize; if (size_tot <= sizeof(buf)) { rsizep = buf; freep = NULL; } else if ((rsizep = freep = malloc(size_tot)) == NULL) { perror("malloc"); return 1; } memset(rsizep, 0x00, size_tot); *rsizep = rsize; rmaskp = (unsigned *)(rsizep + 1); inheritp = rmaskp + rsize; /* * Both masks set to 0 means get the current * values without alteration. */ if (ThreadCtl(_NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT, rsizep) == -1) { perror("_NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT"); free(freep); return 1; } /* * Restrict our inherit mask to the last cpu; leave the * runmask unaltered. */ memset(rsizep, 0x00, size_tot); *rsizep = rsize; RMSK_SET(_syspage_ptr->num_cpu - 1, inheritp); if (ThreadCtl(_NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT, rsizep) == -1) { perror("_NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT"); free(freep); return 1; } free(freep); return 0; }
ThreadCtl(_NTO_TCTL_THREADS_CONT, 0)
Unfreeze all threads in the current process that were frozen using the _NTO_TCTL_THREADS_HOLD command.
ThreadCtl(_NTO_TCTL_THREADS_HOLD, 0)
Hold all threads in the current process except the calling thread.
Threads created by the calling thread aren't frozen. |
These calls don't block.
The only difference between these functions is the way they indicate errors:
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | No |
Signal handler | Yes |
Thread | Yes |
InterruptDisable(), InterruptEnable(), InterruptMask(), InterruptUnmask(), pthread_getname_np(), pthread_setname_np()