[cairo] How to avoid globals?

Robert Norris rob at cataclysm.cx
Thu Feb 7 12:31:38 PST 2008


I'm very close to completing my port of cairo to AROS. Last night I did
the necessary stuff to make it into a shared library. On the first run,
it worked fine; on the second it crashed spectacularly.

AROS currently has no support for .data section globals in shared
objects. A shared library is required to do its own synchronisation and
management of global-style data. This is usually done in AROS-native
libraries by giving each user ("opener") of the library their own
private chunk of memory to store global data in. A library context, if
you like.

I hadn't worried about it too much because I'd looked through cairo
before I started and hadn't seen any globals that looked like they'd be
a problem. I overlooked the pattern and surface caches in
cairo-pattern.c, which are now giving problems.

When a process exits in AROS, the memory it allocates is freed, and a
"close library" function in each of the libraries it is using is called
which is expected to cleanup any shared state in the library. The
library is not necessarily removed from memory at this point (and
certainly not if its in use by other processes).

When cairo starts it clears the caches. Because they were used
previously, they can't be guaranteed to be zero. The array still has
pointers to areas of memory that were allocated by the previous process
and have now been freed, but more importantly, the size is non-zero.
cairo tries to free things, the allocator notices that the calling
process never allocated them, and everything explodes.

I have two options at this point: implement support for globals in AROS,
or find a way to remove those globals from cairo. The first I've already
planned, but there's at least a months' work there that I don't have
time for right now. The major complication is that we can't assume a MMU
is present.

The easist way to remove the globals is to simply add a #ifdef that
causes the cache structures to not appear and the cache functions to
become no-ops. I'm sure it will affect performance but I want to just
get it working first.

The other way would be to wrap the declaration and access to the globals
in some macros that will allow to me to arrange for it to be stored in
the library context. These would be no-op macros everywhere else.

Which approach would be the least offensive? I don't want to just do a
dirty hack since I'm working towards having this code included in the
main distribution.

Looking closer just now, I think cairo_scaled_font_map and
cairo_toy_font_face_hash_table will suffer the same problems.
_cairo_lfsr_random_state should not be an issue as changes to it should
be atomic, though I don't know if multiple processes using the same
table will affect its semantics at all.

Any and all advice greatly appreciated.

Cheers,
Rob.


More information about the cairo mailing list