0
votes

I have multithreaded app where each thread create its own surface, render content, save it and destroy all.

However, after some time (eg. 20 images is saved), the app stucks in _cairo_atomic_init_once_enter from cairo-atomic-private.h.

Here is stack-trace from Visual Studio:

[Inline Frame] app.exe!_cairo_atomic_init_once_enter(unsigned int *) Line 409   C
app.exe!_cairo_image_spans_compositor_get() Line 3135   C
[Inline Frame] app.exe!_cairo_image_surface_init(_cairo_image_surface *) Line 176   C
app.exe!_cairo_image_surface_create_for_pixman_image(pixman_image * pixman_image=0x0000023c1d1f31f0, pixman_format_code_t pixman_format=PIXMAN_a8r8g8b8) Line 197   C
app.exe!_cairo_image_surface_create_with_pixman_format(unsigned char * data=0x0000000000000000, pixman_format_code_t pixman_format=PIXMAN_a8r8g8b8, int width, int height, int stride=-1) Line 355  C
app.exe!cairo_image_surface_create(_cairo_format format, int width, int height) Line 403    C

and I am calling:

surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, int(w), int(h));

My parallel loop is done via:

std::vector<int> xSeq(countX); 
std::iota(std::begin(xSeq), std::end(xSeq), 0); // Fill with 0, 1, ..., countX.
std::for_each(std::execution::par, std::begin(xSeq), std::end(xSeq), [&](auto x)
{
    //create cairo surface, write to it, store it and release it
}

If I run serial version, all is working correctly.

Edit: To store surface to image, I dont use internal PNG saver. I have my own implementation, that is based on:

cairo_surface_flush(surface);
data = cairo_image_surface_get_data(surface);

data contains raw data from cairo and I process them manually and store them with my own compression system.

In some cases, I also use the same system to "inject" data to cairo surface. I obtain data pointer, manually rewrite some pixels and call cairo_surface_mark_dirty(surface) to notify Cairo about the change.

1
Can you add the code which store the surface object to the pixemap?Daniel Kovachev
@DanielKovachev See my edit.Martin Perry
Which image is the one getting stuck? I mean, is it a leftover from the first parallel batch blocking the executor, or is it one of the later iterations?Ext3h
The one from later iteration. Eg. the one I am newly creating.Martin Perry

1 Answers

1
votes

This is not really an answer, but the behaviour you are seeing should be impossible.

_cairo_image_traps_compositor_get has a cairo_atomic_once_t variable that is used to protect some initialisation. Since it is static, we can be sure that no other code touches this variable.

https://github.com/freedesktop/cairo/blob/52a7c79fd4ff96bb5fac175f0199819b0f8c18fc/src/cairo-image-compositor.c#L1270-L1304

_cairo_atomic_init_once_enter checks if the once is already initialised and then just returns 0 / false. Since you say you already had 20 successful calls, the initialisation must already be done. Else, the 20 other calls should not have worked.

https://github.com/freedesktop/cairo/blob/52a7c79fd4ff96bb5fac175f0199819b0f8c18fc/src/cairo-atomic-private.h#L398-L411

Per the above... this should not be possible to occur, right? Unless something overwrites some memory that it should not touch and the value of the once gets corrupted, or something like that. Alternatively, this is some kind of mis-compilation that occurs for reasons I do not understand. Did you compile cairo yourself, or where did you get it from?