I have two functions for allocating and deallocating timers.
Allocate timer allocates a timer and returns an int to the timer that has been allocated
int allocate_timer(void)
{
int count = 0;
int allocated = 0;
/*Loop to find the first timer that is not allocated*/
for(count = 0; count< ARRAY_SIZE; count++)
{
if(allocated_timers[count] == '0')
{
/*When the next timer available timer is found it is set to allocated and timer is set to zero*/
allocated_timers[count] = '1';
timers[count] = 0;
break;
}
else if(allocated > ARRAY_SIZE - 1)
{
printf("No timers available\n");
exit(0);
}
else
{
allocated++;
}
}
/*Position of the allocated timer is returned*/
return count;
}
Deallocating timer, takes in an int to the position that is going to be deallocated
void deallocate_one_timer(int position)
{
if(TIMER_ALLOCATED == allocated_timers[position])
{
allocated_timers[position] = '0';
timers[position] = 0;
}
}
I can’t see away to make them anymore robust than they already they are.
Any advice on how to make them better?
The variable
allocatedis always equal tocount(so could be removed), and IMO it’s potentially confusing to use'0'and'1'as the values in theallocated_timersarray. Usually it would be0and1.Neither of them affects the robustness of the code as it is, but the easier the code is to understand, the more robust it is against future modification.
When you have two “parallel” arrays, like you do here where each timer has an entry in
timersand a corresponding entry inallocated_timers, it is worth considering whether it would be better to have a single array of astructwith two members (in this case perhaps namedvalueandallocated). Sometimes it isn’t better, but often it aids understanding of the code because readers don’t have to discover and remember that these two arrays are closely related.deallocate_one_timercould be made slightly more robust against erroneous use by callers, if it checked thatpositionis within the range0toARRAY_SIZEbefore using it as an array index. I’m not saying that functions have a responsibility to do those checks, but they sometimes help diagnose bugs elsewhere. You can useassertfor non-essential checks like this.asserthas two benefits. First it self-documents that the check isn’t this function’s responsibility to handle, merely that you’re checking someone else did what they should have. Second, you can easily disable all asserts in non-debug builds of your program if you need to make it smaller or faster.Similarly it might be helpful to exit with an error message if a timer is deallocated that is not currently allocated, because that’s likely to indicate a potential problem. Whoever deallocates it twice might do so either side of somebody else allocating it, which means that somebody else suddenly finds they no longer have exclusive use of their timer.
Finally, you set
timers[index]to 0 both on allocate and on deallocate. Nothing particularly wrong with that except that it confuses the issue of which function is actually responsible for ensuring that a newly-allocated timer has the correct initial value. The deallocate function could do nothing, or it could set the timer to a value that’s impossible for an allocated timer to hold (maybe -1, assuming timers go up from 0), so that when debugging you can know immediately that if you’re using a timer whose value is -1, something has gone wrong.Finally finally, this code (obviously) isn’t thread-safe, which I suppose is a kind of non-robustness. There’s no shame in writing code that can’t be used in multi-threaded programs, especially with embedded systems that may not even have the capacity to create threads. Just so long as it’s a deliberate decision, and is documented.