[cairo] Re: Thread-specific linked-list for locked FT_Face objects

David Turner david at freetype.org
Tue Feb 13 14:21:37 PST 2007


ok, just to inform you that I've started coding something like what
I've described in my previous e-mail. I'll try to send a patch in a couple
of days when it's finished.

Regards,

- David

On Tue, 13 Feb 2007 23:19:49 +0100, "David Turner" <david at freetype.org> said:
> On Tue, 13 Feb 2007 14:22:47 -0500, "Owen Taylor" <otaylor at redhat.com>
> said:
> > My worry about this approach is deadlocks:
> > 
> >  cairo_scaled_font_create()
> > 
> > for example, does:
> > 
> >  _cairo_scaled_font_map_lock();
> >  [... call into backend ]
> >  _cairo_scaled_font_map_unlock();
> > 
> > With an exposed cairo_ft_lock(), this would create a potential deadlock
> > if anybody called cairo_scaled_font_create() after locking the FT lock,
> > since you then have both lock orders:
> > 
> >  - Lock the font map; Lock the FT lock
> >  - Lock the FT lock; lock the font map
> > 
> > A complicated set of rules about what functions you could call with 
> > FT locked would be a invitation to all sorts of subtle hard-to-reproduce
> > problems.
> > 
> 
> I think that this is solvable by a different approach. Basically,
> you need to synchronize access/usage to the FreeType API and data
> structures, but the locking doesn't need to be pushed back to the
> cairo font structures themselves, only to their operations when
> they act on a FT_Face or FT_Size.
> 
> In other words, you need to separate the ownership of FT_Library,
> FT_Face and FT_Size objects from the rest of Cairo data structures.
> Consider this example:
> 
>  /* an opaque structure that holds a FT_Library, a small
>   * MRU-ordered list of FT_Face and FT_Size objects, all
>   * protected by a mutex/lock
>   */
>   typedef struct cairo_ft_state     cairo_ft_state_t;
> 
>  /* grab the FreeType state from Cairo, this is a potentially blocking
>   * call that locks the state's mutex. this must be done by any routine
>   * that uses a FT_Face or FT_Size object within Cairo
>   */
>   cairo_public  cairo_ft_state_t*
>   cairo_ft_state_lock(void);
> 
>  /* get FT_Library from FreeType state
>   */
>   cairo_public FT_Library
>   cairo_ft_state_get_library (cairo_ft_state_t  *ft_state);
> 
>  /* retrieve a FT_Face for a given ft_font_face, you shouldn't
>   * assume anything about its mutable state.
>   */
>   cairo_public FT_Face
>   cairo_ft_state_get_face (cairo_ft_state_t      *ft_state,
>                            cairo_ft_font_face_t  *ft_font_face);
> 
>  /* retrieve a FT_Size for a given ft_scaled_font
>   * the corresponding FT_Face can be accessed directly as size->face.
>   * the returned FT_Size is already activated, so there is no need
>   * to call FT_Size_Activate.
>   */
>   cairo_public void
>   cairo_ft_state_get_size (cairo_ft_state_t        *ft_state,
>                            cairo_ft_scaled_font_t  *ft_scaled_font,
>                            void                   **psize_ref);
> 
>  /* release a FreeType state, release/recycle the corresponding
>   * FT_Face and FT_Size that were extracted with cairo_ft_state_get_face
>   * and cairo_ft_state_get_size, then unlock the state's mutex
>   */
>   cairo_public  void
>   cairo_ft_state_unlock (cairo_ft_state_t  *ft_state);
> 
> the important point is that cairo_ft_font_face_t should hold *no* pointer
> to
> a FT_Face, similarly, ft_scaled_font shouldn't hold any pointer to a
> FT_Face
> or FT_Size object.
> 
> the same is true of glyph caching, i.e. cairo_unscaled_font_t must be
> changed
> to not hold a FT_Face, instead one should be obtained through
> ft_state_lock()
> and ft_state_get_face/size() when a glyph needs to be loaded.
> 
> there is an additionnal detail to consider, which is that a
> cairo_font_face
> can be created from cairo_font_face_create_for_ft_face() where the caller
> provides its own FT_Face to Cairo. I assume that in this case, the
> FT_Face
> is owned by a different FT_Library, and can be stored directly in the
> cairo_font_face_t object, as a special exception.
> 
> cairo_ft_scaled_font_lock_face() and cairo_ft_scaled_font_unlock_face()
> cannot
> be used in a thread-safe way and will probably need to be deprecated. I
> wonder
> how many Cairo client are using them though... every code that uses them
> is
> already broken anyway.
> 
> similarly, all operations that need to access FT_Face/FT_Size objects
> would
> lock the cairo_ft_state_t, get the objects from it, perform access/calls
> on
> them, then release the state.
> 
> > > An alternative would be to wrap more of the FreeType API in cairo
> > > cloathing and perform the necessary locking within the cairo library;
> > > this doesn't seem commensurate with the current pango implementation
> > > though, which shares FreeType usage across several output modules.
> > 
> > I'm not sure what you mean by this. Right now, Pango exposes the ability
> > to get a FT_Face in the public API. (Actually, not fully public API, but
> > rather reduced-stability engine-and-backend API.) No matter what
> > approach we take, that can't be made thread-safe as long as FreeType
> > is not thread-safe.
> >
> 
> The FreeType API cannot be made thread-safe, consider the following
> sequence
> of operations:
> 
>   FT_Size_Activate(size);
>   FT_Set_Transform(size->face, some_transform);
>   FT_Load_Glyph(size->face, some_glyph, some_flags);
> 
> if two threads are trying to do the same operations on two distinct
> FT_Size
> objects related to the same parent FT_Face, you have pretty nice race
> conditions
> everywhere unless you can wrap these around a lock that synchronizes
> access to
> the corresponding FT_Library
> 
> > But almost anything that Pango does with FreeType can (theoretically) be
> > reduced to atomic operations that could be individually wrapped by
> > cairo.
> > 
> I don't see why cairo-pango couldn't use the cairo_ft_state_t itself. I
> suppose
> that it holds references to FT_Face and maybe FT_Size objects internally,
> but
> it could be modified not to.
> 
> On the other hand, I'm more worried about the API that provides a
> FT_Face, who
> owns it after the call ? what about the corresponding FT_Library ? I am
> right to
> assure that Pango uses its own FT_Library, independent from the Cairo one
> ?
> 
> > The most problematical part might be harfbuzz, which needs access to
> > entire raw tables from the FreeType font. There's no problem with doing
> > that with an API that simply copies the data out of the font into a
> > malloc'ed segment, but if you wanted to try and share the mmap's that
> > FreeType creates, then things get trickier.
> > 
> the tables are read-only, I don't see exactly what the problem would be.
> At worse, you could simply re-map part of the font files into your own
> memory segments and read directly from them, independent of the lifetime
> of the FT_Face objects themselves...
> 
> 
> Hope this helps,
> 
> - David Turner
> - The FreeType Project  (www.freetype.org)
> _______________________________________________
> cairo mailing list
> cairo at cairographics.org
> http://cairographics.org/cgi-bin/mailman/listinfo/cairo


More information about the cairo mailing list