Edit: we're using C99.
First, some setup/information for context. I'm writing an API in C that wraps around a C checksum API that utilizes IUF (Initialize(), Update(), Finalize()) functions.
My API contains one function, we'll call it foo(), that takes an input structure pointer as a parameter. It was written in such a way that the data being hashed can be provided in blocks/chunks instead of the entire data buffer. This code will run on an embedded system with very limited resources, so being able to read files in chunks to hash the data is the specific purpose of this API. Using a single function is not my choice, but a requirement.
int foo(struct_t*);
And struct_t looks like this.
{
char* data,
int dataLen,
bool finalBlock,
char checksum[CHECKSUM_SIZE]
}
Basically, the caller of foo() fills in the 'data' and 'dataLen' parameters with the next block of data and the size of that data accordingly each time they call the function until the data has been fully provided to foo(). The 'finalBlock' parameter is unfortunately the only way to tell foo() that you are providing the final chunk of data to be processed. This is understood and okay for the use cases.
Now to the real problem. The inner IUF checksum API has a unique data structure of it's own that I am not allowed to expose to the callers of foo(). Since we're only using foo() in one thread right now, the current solution was to make the IUF API's structure (we'll call it bar) a static variable. This makes the foo() function not thread safe.
int foo(struct_t* x)
{
/*Struct required by IUF API*/
static bar y = {0};
int retCode = 0;
/*rest of code that processes data as needed*/
...
/*after finalizing checksum and storing in x, reset y*/
return retCode;
}
I'd like to make foo() thread-safe if at all possible, without exposing the 'bar' structure to the caller's of foo(). Any suggestions?
TL;DR: Have an API with one function that requires multiple calls to finish job. Have to hide internal structure from caller of this API, but the structure has to persist until the API has completed fully. Currently setting that structure as a static variable so it stays around until API is finished, but this makes my API not thread safe. Help please.
There are two basic ways to structure this:
Grant exclusive access to the whole subsystem to one thread at a time. You can achieve this with the help of a mutex and a condition variable, which can be static members of foo()
if you like. This is invisible to callers, but it prevents all concurrency, even in between foo()
calls in the multi-block case.
Give each thread its own data. This is what you want if you cannot accommodate non-concurrency of foo()
.
Even without access to C11's built-in thread-local data support, it may be that whatever threading API you're using has a TLD mechanism or a substantial equivalent. In particular, pthreads does, if that happens to be what you're using. You could probably even roll your own with the help of a hash table.
But since you're writing for a resource-constrained system, you're probably interested in lightweight approaches, and the absolute lightest-weight approach would be to have each thread provide its own data by giving struct_t
a bar
for a member. Not only does this sidestep whatever kind of indirection or lookup would be involved in accessing the per-thread data, but it also can avoid any dynamic memory allocation. But this does expose bar
to foo
's callers, which you say you must not do.
Between those, you have the alternative of having foo
allocate bar
s, and hand them off opaquely to the caller, with the expectation that they be returned on each associated call. This may be the best fit for your needs, and it's where I'll focus the rest of this answer.
To implement such an approach, first give struct_t
an additional member to store the context data:
struct struct_t {
char* data;
int dataLen;
bool finalBlock;
char checksum[CHECKSUM_SIZE];
void *state; // <-- this
};
The caller is expected to set state
to a null pointer for the initial call of a sequence (which is how foo
can recognize that, which I don't otherwise see a provision for), and on subsequent calls to pass back whatever value foo
provided in it. The natural calling pattern would thus look something like this:
struct struct_t checksum_state = { 0 };
int result;
checksum_state.data = some_data;
checksum_state.dataLen = the_length;
result = foo(&checksum_state);
// ... check / handle result ...
checksum_state.data = more_data;
checksum_state.dataLen = new_length;
result = foo(&checksum_state);
// ... check / handle result ...
checksum_state.data = last_data;
checksum_state.dataLen = last_length;
checksum_state.finalBlock = 1;
result = foo(&checksum_state);
// ... check / handle result ...
// ... use checksum_state.checksum ...
I presume that that's about what you already have for a usage pattern, and I note that it does not require the caller to explicitly use or acknowledge checksum_state.state
at all, though that is accomplished in part by the caller using an initializer instead of per-member initialization.
On the foo()
side, it would be structured something like this:
int foo(struct_t* x) {
int retCode = 0;
struct bar *y;
if (!x->state) {
x->state = calloc(1, sizeof(struct bar));
if (!x->state) // ... handle allocation error ...
}
y = x->state;
/* Do stuff with x and y */
if (x->lastBlock) {
free(x->state);
}
return retCode;
}