1. Field of the Invention
The present invention relates to tools for software development.
2. Discussion of the Related Art
In a multitasking software system, multiple tasks (and interrupt service routines) can execute simultaneously or appear to execute simultaneously. In a system with multiple processors, single tasks can execute simultaneously on each processor. In systems with processors that contain multiple execution units and redundant register sets, multiple tasks can execute simultaneously on the single processor. On traditional processors, an operating system can arbitrarily allocate short amounts of time to each processor to execute specific tasks. Though only one task executes at any given time, the tasks appear to execute simultaneously, and execution can begin and pause at any arbitrary software instruction in the task source code. Interrupt service routines can be treated as additional tasks for the purpose of the analysis that follows.
There are certain hazards, called race conditions, that occur in these multitasking systems and that can produce incorrect results. Race conditions occur when one task accesses a shared variable or a shared resource while at or around the same time another task accesses the same shared variable or resource.
Line 108 is the declaration of the task2 task. Line 109 executes after task2 has performed its function at which time the global variable task_count is incremented. The curly bracket at line 110 signifies the end of task2.
Since it is not possible to know when task1 and task2 instructions will execute with respect to each other, it is possible for line 103 of task1 to execute before task2 has begun and lines 105 and 106 of task1 to execute after task2 has completed. In this case, suppose task_count already has some value x representing the number of times the tasks have executed. When line 101 is executed, local variable count gets the value x. Then task task2 executes and at line 109, task_count is incremented to x+1. After task2 completes, line 105 increments count to x+1 and line 106 stores count into task_count. At this point, the variable task_count has the value x+1 rather than the correct value x+2.
One can argue that task1 should not be written using a local variable to store the value of a global variable or that the operation of incrementing the global variable should not be performed by instructions spread throughout the task. Nevertheless, this action is allowed and can be written in this way knowingly or inadvertently. Also, even when a single increment is coded, such as line 109, this high level increment instruction typically is compiled into several low-level assembly instructions that store the variable in a register, increment the register, and store the new value back to the global variable. This sequence can be also be interrupted by another task and thus does not protect against race conditions.
In a multitasking system it is possible for task 1 and task 2 to be executing simultaneously. In this case, characters from buffer in task1 and message in task2 will be interspersed in the output to the printer port, resulting in a printout that is unreadable.
In order to protect against multiple tasks accessing shared resources simultaneously, the prior art makes use of mutexes or interrupt disabling. Mutexes are data structures that are defined by operating systems and used by tasks to ensure exclusive access to shared resources. Similar data structures called binary semaphores and counting semaphores can generally be used in place of mutexes, with appropriate initialization. A mutex for a shared resource is set in one task to signal that the particular resource is in use and that another task should not use it. The mutex is reset when the task is done with the shared resource, allowing other tasks to use it. Any task wishing to use a shared resource must first check the mutex for the resource and wait for the mutex to be reset.
The problem with using mutexes (or semaphores) is that programmers must be aware of all shared resources and must correctly insert code to set, reset, and check the mutexes. Much debugging time is spent in a multitasking system because a programmer has not correctly understood or correctly written the code for controlling the mutexes, resulting in errors that can only be discovered when the code has been compiled and run under the appropriate conditions. These appropriate conditions include a program state and a set of inputs that causes several tasks to access the shared resource simultaneously, which may not occur often, if at all, during testing of the system.
The present invention provides a system and a method that examine computer program source code for a multitasking system and automatically protects shared resources such as shared variables and shared hardware from being accessed by one task while in the process of being accessed by another task. The present invention provides a method of automatically protecting shared resources without requiring the programmer to understand or implement the protection mechanism. The present invention improves the reliability of a multitasking software system and decreases the time spent debugging such a system.
The present invention provides a software tool that examines all the source code for a multitasking system and creates a list of all global resources in that system. The tool then examines the source code for each task in the system and identifies all shared global resources that are accessed by more than one task. The tool then places protection code around sets of instructions that access each such shared global resource, protection code being code that allows access to the shared resource without interruption by other tasks.
Further features and advantages of various embodiments of the present invention are described in the detailed description below, which is given by way of example only.
The present invention will be understood more fully from the detailed description given below and from the accompanying drawings of the preferred embodiment of the invention, which, however, should not be taken to limit the invention to the specific embodiment but are for explanation and understanding only.
The present invention will be understood more fully from the detailed description given below and from the accompanying drawings of the preferred embodiments of the invention, which, however, should not be taken to limit the invention to the specific embodiments but are provided for explanation and understanding only.
The present invention provides a software tool that examines all the source code for a multitasking system and that creates a list of all shared resources in that system. In one embodiment, the tool performs multiple passes examining the source code for the system in the manner shown in
In one embodiment of the tool, the tool considers each function to be a task in the multitasking system and places protection statements around each function call. This assumption results in correct operation but may not be efficient. In another embodiment, the tool is aware of all the tasks that are running on top of the operating system. The tool can determine these tasks in several ways. In one embodiment the tool is aware of operating system calls that are used to begin execution of tasks. The tool can search the system source code for all these OS calls to determine which routines are tasks in order to place protection statements around each task call. In another embodiment, the OS has a table that lists all the tasks in the system, and the tool examines these tasks. In another embodiment, the user places special directives, comments, or other kinds of programming statements in the code for each task, which the tool finds when examining the system source code. In another embodiment, the user creates a configuration table that lists all the tasks in the system. The tool can determine these tasks, to protect them, in other ways that are known to one of ordinary skill in the art.
At block 706, if the tool is not inside a task, it progresses to block 709, where it checks whether the statement is a resource declaration such as the declaration of a global variable. If the statement is a resource declaration, the tool progresses to block 710 where it adds the resource to the resource list, Global_List 610, and goes back to block 703. At block 709 if the statement is not a resource declaration! the tool progresses to block 711, where it determines whether the source code line is a task declaration. If the line is not a task declaration, the tool goes back to block 703. Otherwise the tool progresses to block 712 where it sets the task flag and then goes back to block 703. In cases where tasks consist of nested routines and functions, keeping track of the beginning and the end of tasks requires additional steps that are not specifically included in this flowchart, but in general terms the flowchart is the same.
Once all the source code has been examined by the tool and the list of global variables 610 is complete, the tool creates a new list of numbers, with each number representing the number of tasks that access a corresponding global variable, as shown by list Count_List 800 in
Next the tool examines the list Count_List 800. For each entry in the list Count_List 800 that has a value of 0 or 1, the list entry is eliminated and the corresponding entry in the list Global_List 610 is eliminated. Also, for each entry in the list Count_List 800 that has a value of 0 or 1, the corresponding entries in the “first” and “last” lists 810 for each task in the system are eliminated. An example result is shown in modified lists Global_List 820, Count_List 830, and first/last lists 840 that were generated from original lists Global_List 610, Count_List 800, and first/last lists 810.
In block 905, if the task flag is set, which signifies that the tool is reading source code from inside a task, the tool progresses to block 909, where it checks whether the source code line is accessing a resource in the global resource list, Global_List 610, which was created in the first pass. If the source code line is not accessing a resource in the global resource list, the tool progresses to block 914, where it checks whether the current source code line is an end-of-task statement. If the line is not an end-of-task statement, the tool goes back to block 903. Otherwise the tool progresses to block 915, where it clears the task flag and then goes back to block 903.
In block 909, if the source code line is accessing a resource in the global resource list, Global_List 610, the tool progresses to block 910, where it checks whether the specific global resource being accessed has been accessed by a previous line of source code in the current task and was thus already noted by the tool. This checking is done simply be checking whether the entry for the particular global resource in the “first” list of the first/last lists 810 is non-zero. If the specific global resource has already been accessed by a line of source code in the current task and was thus already noted by the tool, the tool progresses to block 913, where it places the current line number in the “last” list of the first/last list 810 that corresponds to the specific global resource. The tool then goes back to block 903.
When the tool is in block 910 and the specific global resource has not already been accessed by a line of source code in the current task, the tool progresses to block 911 where it increments the entry in Count_List 800 that contains the number of tasks that access the corresponding global variable in list Global_List 610. The tool then progresses to block 912 where it places the current line number in a position in the “first” list of the first/last list 810 that corresponds to the specific global resource. Then the tool progresses to block 913, where it places the current line number in the “last” list of the first/last list 810 that corresponds to the specific global resource. The tool then goes back to block 903.
In block 903, if the end of the source code has been reached, the tool progresses to block 916, where it goes through each entry in Global_List 610, Count_List 800, and the first/last lists 810 for each task, eliminating all entries in all lists where the count in Count_List 800 equals 1 or 0. The count signifies that only one task accesses the resource or no task accesses the resource, respectively. In these cases, protection is unnecessary. The new lists, after eliminating entries, are the modified lists Global_List 820, Count_List 830, and first/last lists 840. The tool then progresses to block 917, which is the end of this pass.
In a third pass 503, the tool examines the source code for the system a third time. The tool notes each line of code where a task accesses a shared global variable in the modified list Count_List 830. As shown in
In block 1106, if the line of source code is a task declaration, the tool progresses to block 1107 where the tool records the name of the task. The tool then progresses to block 1108 where it sets the task flag, which signifies that source code is being read from a task. The tool then progresses to block 1109, where it writes the line of source code to the file that is the output of the tool and then it goes back to block 1103.
When the tool is in block 1105 and the task flag is set, which signifies that source code is being read from a task, the tool progresses to block 1110 where it tests whether the current line number corresponds to the number in the “first” list associated with the current task. If the line number does correspond, the tool progresses to block 1111, where it writes an initial protection statement to the output file. Then the tool progresses to block 1112, where it writes the line of source code to the output file. In block 1110, if the current line number does not correspond to the number in the “first” list associated with the current task, the tool progresses directly to block 1112, where the tool writes the line of source code to the output file.
From block 1112 the tool progresses to block 1113, where it tests whether the current line number corresponds to the number in the “last” list associated with the current task. If the line number corresponds, the tool progresses to block 1114, where it writes an ending protection statement to the output file and then progresses to block 1115. In block 1113, if the current line number does not correspond to the number in the “last” list associated with the current task, the tool progresses directly to block 1115. In block 1115 the tool checks whether the current source code line is an end-of-task statement. If the line is an end-of-task statement, the tool progresses to block 1116 where it clears the task flag, which signifies that the tool is no longer reading source code in a task. The tool the goes back to block 1103. In block 1115 if the current source code line is not an end-of-task statement, the tool goes back to block 1103.
In another embodiment of the tool, the third pass is more efficient about placing protection code around accesses of shared global variables.
In yet another embodiment of the tool, the third pass is more efficient about placing protection code around accesses of shared global variables.
In
As described above, mutexes can be the protection mechanism used so that the shared resource can be used by one section of code at any given time. In cases where a shared resource is used by an interrupt service routine (ISR), interrupt masking can be used for protection. Interrupt masking is a way to turn off interrupts in software. If shared resource R is used by the ISR that services interrupt I, any accesses of resource R (outside the ISR for I) will begin with a statement that masks interrupt I and will end with a statement that enables interrupt I. In this way, if interrupt I occurs during the section of code that accesses R, the interrupt will not be serviced until the section of code has completed executing and the access of R has completed.
In yet another embodiment of the tool, a programming language parser is used as an initial pass of the tool to translate the user's source code into an abstract, intermediate form representing the semantics of the application independent of the syntax of the programming language. The three passes of the tool act on this abstract representation rather than the original source code. The abstract representation can be easily examined to identify shared resources. The abstract representation can give a clear representation of the program flow including alternate execution branches. The abstract representation can also be examined to efficiently identify all locations in the source code where these shared resources are initially accessed, and thus need to be protected, and all locations in the source code where these shared resources are released, and the protection can be turned off. By using a single intermediate form, a new programming language can be accommodated simply by writing a new parser for that language. Using a programming language parser allows the tool to support multiple languages without having to rewrite the transformations previously described for each language. Using a programming language parser also allows users the capability of writing their application in more than one programming language.
With respect to the present invention, the protection mechanism can be implemented in many different ways. Other software mechanisms for protection of shared variables, shared hardware resources, and critical sections within functions that may be called by two or more tasks simultaneously may be implemented in several ways that are well known to one of ordinary skill in the art.
Various modifications and adaptations of the operations that are described here would be apparent to those skilled in the art based on the above disclosure. Many variations and modifications within the scope of the invention are therefore possible. The present invention is set forth by the following claims.