This is a concept question regarding gtk/glib/libpango/libcairo
. Let's straight to the problem.
I am wrapping an old C library in Go written by a former colleague, somewhere in the C code calls pango_cairo_font_map_get_default()
to get a default font_map
maintained by libpango
.
The wrapping is basically from Go domain entering the C domain (foreign function interface) and C side using pthread
creates a thread eventually calls pango_cairo_font_map_get_default
.
Originally, everything works fine on the pure C side. After the wrapping, the C code stuck on the calling of pango_cairo_font_map_get_default()
printf("before call");
font_map = pango_cairo_font_map_get_default();
printf("after call");
The expected outputs are:
before call
after call
The actual outputs are:
before call
(process:1): GLib-GObject-WARNING **: cannot register existing type 'PangoFontMap'
(process:1): GLib-CRITICAL **: g_once_init_leave: assertion 'result != 0' failed
(process:1): GLib-GObject-CRITICAL **: g_type_register_static: assertion 'parent_type > 0' failed
(process:1): GLib-CRITICAL **: g_once_init_leave: assertion 'result != 0' failed
(process:1): GLib-GObject-CRITICAL **: g_type_register_static: assertion 'parent_type > 0' failed
(process:1): GLib-GObject-WARNING **: cannot register existing type 'PangoCairoFontMap'
My own simulation (The C side basically explains how my former colleague was doing with libpango
) demo works fine, no warning and no critical outputs:
package main
/*
#cgo CFLAGS: -I/usr/local/include/pango-1.0
#cgo CFLAGS: -I/usr/local/include/glib-2.0
#cgo CFLAGS: -I/usr/local/include/cairo
#cgo LDFLAGS: -L/usr/local/lib -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lglib-2.0
#include <pango/pangocairo.h>
#include <stdio.h>
#include <pthread.h>
void hello() {
printf("threa id: %li
", (unsigned long int)pthread_self());
PangoFontMap* font_map = pango_cairo_font_map_get_default();
PangoFontDescription* font_desc = pango_font_description_new();
pango_font_description_set_family(font_desc, "monospace");
pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL);
pango_font_description_set_size(font_desc, 20 * PANGO_SCALE * 700 / 96);
PangoContext* context = pango_font_map_create_context(font_map);
PangoFont* font = pango_font_map_load_font(font_map, context, font_desc);
PangoFontMetrics* metrics = pango_font_get_metrics(font, NULL);
int width = pango_font_metrics_get_approximate_digit_width(metrics) / PANGO_SCALE;
int height = (pango_font_metrics_get_descent(metrics)
+ pango_font_metrics_get_ascent(metrics)) / PANGO_SCALE;
printf("%d, %d
", width, height);
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
cairo_t* cairo = cairo_create(surface);
cairo_set_source_rgb(cairo, 155 / 255.0, 155 / 255.0, 155 / 255.0);
cairo_rectangle(cairo, 0, 0, width, height);
PangoLayout* layout = pango_cairo_create_layout(cairo);
pango_layout_set_font_description(layout, font_desc);
g_object_unref(layout);
cairo_destroy(cairo);
cairo_surface_destroy(surface);
}
void* font() {
hello();
hello();
return NULL;
}
void two_threads() {
pthread_t thread1;
pthread_create(&thread1, NULL, font, NULL);
pthread_join(thread1, NULL);
pthread_t thread2;
pthread_create(&thread2, NULL, font, NULL);
pthread_join(thread2, NULL);
}
*/
import "C"
import "sync"
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 1; i++ {
wg.Add(1)
go func() {
C.two_threads()
wg.Done()
}()
}
wg.Wait()
}
TL;DR: my understanding of pango_cairo_font_map_get_default()
will always succeed (thread safe, because it is using 1.40.4 1.el7), and no matter how many times (static internal variable inside pango) the code tries to call.
Thus, my questions are:
- what can be a cause of
cannot register existing type
/g_once_init_leave: assertion failed
? - why such an error blocks the code?