The threads window displays the set of executing contexts on the target processor structured as a set of queues. The threads window is populated using the threads script which is a JavaScript program store in a file that has a file type property of "Threads Script" (or is called threads.js) and is in the project that is being debugged.
On start debugging the threads script is loaded and the function init() is called that will determine the columns that are displayed in the threads window.
When the application stops on a breakpoint the function update() is called which creates entries in the threads window corresponding to the columns that have been created together with the saved execution context (register state) of the thread. By double clicking on one of the entries in the threads window the debugger is located to it's saved execution context - you can put the debugger back into the default execution context using Show Next Statement.
Writing the threads script
The threads script controls the threads window using the Threads object.
The methods Threads.setColumns and Threads.setSortByNumber can be called from the function init().
function init()
{
Threads.setColumns("Name", "Priority", "State", "Time");
Threads.setSortByNumber("Time");
}
The above example creates the named columns Name, Priority, State and Time in the threads window and makes the Time column be sorted numerically rather than alphabetically.
If you don't supply the function init() in the threads script then the threads window will create columns Name, Priority and State.
The methods Threads.clear(), Threads.newqueue() and Threads.add() can be called from the function update().
The Threads.clear() method clears the threads window.
The Threads.newqueue() function takes a string argument and creates a new top level entry in the threads window. Subsequent entries that are added to this window will go under this. If you don't call this then the entries will all be a the top level of the threads window.
The Threads.add() function takes a variable number of string arguments which should correspond to the number of columns displayed by the threads window. The last argument to the Threads.add() function should be an array (possibly empty) containing the registers of the thread or alternatively a handle that can be supplied a call to the threads script function getregs(handle) which will return an array when the thread is selected in the threads window. The array containing the registers should have the entries in the order they are displayed in the CPU registers display, typically this will be in register number order e.g. r0, r1, and so on.
function update()
{
Threads.clear();
Threads.newqueue("My Tasks");
Threads.add("Task1", "0", "Executing", "1000", [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
Threads.add("Task2", "1", "Waiting", "2000", [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
}
The above example will create a fixed output on the threads window and is here to demonstrate how to call the methods.
To get real thread state you need to access the debugger from the threads script. To do this you can use the JavaScript method Debug.evaluate("expression") which will evaluate the string argument as a debug expression and return the result. The returned result will be an object if you evaluate an expression that denotes a structure or an array. If the expression denotes a structure then each field can be accessed using the field name.
So if you have a structs in the application as follows:
struct task {
char *name;
unsigned char priority;
char *state;
unsigned time;
struct task *next;
unsigned registers[17];
};
struct task task2 = { "Task2", 1, "Waiting", 2000, 0, { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 } };
struct task task1 = { "Task1", 0, "Executing", 1000, &task2, { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 } };
Then you can update() the threads window using the following
task1 = Debug.evaluate("task1");
Threads.add(task1.name, task1.priority, task1.state, task1.time, task1.registers);
You can use pointers and C style cast to enable linked list traversal.
var next = Debug.evaluate("&task1");
while (next)
{
var xt = Debug.evaluate("*(struct task*)"+next);
Threads.add(xt.name, xt.priority, xt.state, xt.time, xt.registers);
x=xt.next;
}
Note that if the threads script goes into an endless loop then the debugger, and consequently CrossStudio, will become unresponsive and you will need to kill CrossStudio using a task manager. so the above loop is better coded as follows:
var next = Debug.evaluate("&task1");
var count=0;
while (next && count > 10)
{
var xt = Debug.evaluate("*(struct task*)"+next);
Threads.add(xt.name, xt.priority, xt.state, xt.time, xt.registers);
x=xt.next;
count++;
}
You can speed up the threads window update by not supplying the registers of the thread to the Threads.add() function. To do this you should supply a handle/pointer to the thread as the last argument to the Threads.add() function.
If the previous example is modified to use a pointer to the registers:
struct task {
char *name;
unsigned char priority;
char *state;
unsigned time;
struct task *next;
unsigned *registers;
};
unsigned registers[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
struct task task2 = { "Task2", 1, "Waiting", 2000, 0, registers};
struct task task1 = { "Task1", 0, "Executing", 1000, &task2, registers};
Then the previous example call to the update() function will supply the address of the registers to the threads window. When the thread is selected the threads window will call getregs(xt.registers) in the threads script. The getregs function should return the array of registers for example.
function getregs(x)
{
return Debug.evaluate("(unsigned[16])"+x);
}
See threads.js for the threads script used with CTL.