I have specific worries about what is being proposed here:

   - First, the proposed merge requests adds a ton of conditional code
   paths that are impossible to properly review now or even maintain over
   time. Since there is no proper distinction in the source code between what
   is supposed to be shareable+readonly and exclusive+mutable, There is no way
   by looking at the code to determine the *correctness* of the change,
   this will make improving library internals even more difficult in the
   future. It is very likely that this feature is gonna break in subtle ways
   that are very hard to detect beforehand. Given the scope of the library's
   API, I don't think it is possible to come up with an extensive regression
   test that covers every possibility. I am convinced this will not be
   maintainable over time. Sorry.


   - The locking requirements do not only apply to the input stream but to
   any data that is loaded or created on demand. A lot of these have been
   removed to make the library "more thread-safe" (it really isn't). And since
   the FreeType API was designed to use mutable state very intentionally (this
   saves a lot of memory compared to the use of immutable data structures,
   which was important for embedded systems). There is no clear way for a
   client to determine whether a given API will mutate the state, so the only
   safe option for a client is to lock on every API call.


   - Finally, calling these instances "clones" or "copies" is misleading. A
   best they should be called "dependent faces" or "child faces", but the fact
   that they complicate the lifecycle management of many objects is a problem
   in itself.

Just like for multi-thread usage, the only correct way to deal with a
mutable API is to either use locking of a single instance before doing any
mutable operation (be it loading something, or changing some settings), or
to create several FT_Face instances instead. This keeps an already
complicated API manageable without introducing new failure modes.

However, it should be possible to implement a real "cloning" facility that
could be used for safe multi-threaded and variable-fonts usage. As long as
all read-only sharing is hidden from the client, it can be introduced
progressively into the source tree.
What I mean more precisely:

   - An FT_Clone_Face() API that takes an input FT_Face instance and
   returns a new instance that has its own lifecycle (except that they will be
   children of the same FT_Library, and use the same FT_Memory allocator).
   - For the input stream, a way to either clone it, or share it safely
   between instances is needed, and should be provided as an argument to the
   function in some way. We could change the stream implementation used
   internally by the library to make this easier, or we could require the
   client to use FT_Open_Face() with a user-provided shareable stream for
   FT_Clone_Face() to work.
   - The initial implementation would simply re-open the face with the new
   stream, inefficient but completely safe. But this opens the door to
   identifying read-only data in the source face that can be copied directly
   to the clone, saving all the work required to load/validate/compute it.
   - Note that I wrote "copy" above, because for efficient and safe
   read-only sharing, atomic reference counting is required, which is not part
   of C99, hence not portable. However, it can be introduced as a separate
   step by defining the right abstractions (types and macros to operate on
   them). Essentially, we need the equivalent of std::shared_ptr<>, or the
   intrusive versions of it where the ref-count is at the start of the shared
   object, but in C99 instead. For platforms that do not support threads, just
   do non-atomic refcounts.
   - The most important part is being able to progressively increase the
   efficiency of the cloning process in a way that adds read-only sharing in
   an explicit way that is easy to control at review time, or when changing
   the library's internals.







Le ven. 4 févr. 2022 à 17:02, Werner LEMBERG <w...@gnu.org> a écrit :

>
> > This proposal aims to take the best of both approaches by
> > introducing a new function, `FT_Clone_Face`.  [...]
>
> Excellent summary, much appreciated, thanks!
>
> What we are mainly interested in is whether other users would going to
> use the proposed API as advertised.  If yes, please say so.  Otherwise
> it would be great if you could discuss problematic issues with
> Tayyab's approach.
>
>
>     Werner
>
>

Reply via email to