Update Android port

* configure.ac: Check for madvise.
* lisp/international/fontset.el (script-representative-chars):
Improve detection of CJK fonts.
* src/pdumper.c (dump_discard_mem): Use madvise if possible.
* src/sfnt.c (sfnt_map_glyf_table, sfnt_unmap_glyf_table): New
functions.
* src/sfnt.h (struct sfnt_glyf_table): New field.
* src/sfntfont.c (struct sfnt_font_info, sfntfont_open)
(sfntfont_close, sfntfont_detect_sigbus): Allow mmapping fonts
if possible.
* src/sfntfont.h: Update prototypes.
* src/sysdep.c (handle_sigbus, init_sigbus, init_signals):
Initialize SIGBUS correctly.
This commit is contained in:
Po Lu 2023-02-18 11:50:44 +08:00
parent ce440ae92c
commit 265435fdf8
8 changed files with 276 additions and 9 deletions

View file

@ -5722,8 +5722,8 @@ if test "$with_unexec" = yes && test "$opsys" = "haiku"; then
Please use the portable dumper instead.])
fi
# Dump loading
AC_CHECK_FUNCS([posix_madvise])
# Dump loading. Android lacks posix_madvise.
AC_CHECK_FUNCS([posix_madvise madvise])
dnl Cannot use AC_CHECK_FUNCS
AC_CACHE_CHECK([for __builtin_frame_address],

View file

@ -200,7 +200,10 @@
(symbol . [#x201C #x2200 #x2500])
(braille #x2800)
(ideographic-description #x2FF0)
(cjk-misc #x300E #xff0c)
;; Noto Sans Phags Pa is broken and reuses the CJK misc code
;; points for some of its own characters. Add one actual CJK
;; character to prevent finding such broken fonts.
(cjk-misc #x300E #xff0c #x300a #xff09 #x5b50)
(kana #x304B)
(bopomofo #x3105)
(kanbun #x319D)

View file

@ -4747,7 +4747,9 @@ dump_discard_mem (void *mem, size_t size)
# ifdef HAVE_POSIX_MADVISE
/* Discard COWed pages. */
(void) posix_madvise (mem, size, POSIX_MADV_DONTNEED);
# endif
# elif defined HAVE_MADVISE
(void) madvise (mem, size, MADV_DONTNEED);
#endif
/* Release the commit charge for the mapping. */
(void) mprotect (mem, size, PROT_NONE);
#endif

View file

@ -34,6 +34,11 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <string.h>
#include <unistd.h>
#include <setjmp.h>
#include <errno.h>
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#if defined __GNUC__ && !defined __clang__
#pragma GCC diagnostic ignored "-Wstringop-overflow"
@ -1584,6 +1589,91 @@ sfnt_read_glyf_table (int fd, struct sfnt_offset_subtable *subtable)
return glyf;
}
#if defined HAVE_MMAP && !defined TEST
/* Map a glyph table from the given font FD. Use the table directory
specified in SUBTABLE. The glyph data is not byte-swapped.
Value is the glyf table upon success, else NULL.
A mapped glyf table must be unmapped using `sfnt_unmap_glyf_table'.
The caller must correctly handle bus errors in between glyf->table
and glyf->size. */
struct sfnt_glyf_table *
sfnt_map_glyf_table (int fd, struct sfnt_offset_subtable *subtable)
{
struct sfnt_table_directory *directory;
struct sfnt_glyf_table *glyf;
void *glyphs;
size_t offset, page, map_offset;
/* Find the table in the directory. */
directory = sfnt_find_table (subtable, SFNT_TABLE_GLYF);
if (!directory)
return NULL;
/* Now try to map the glyph data. Make sure offset is a multiple of
the page size. */
page = getpagesize ();
offset = directory->offset & ~(page - 1);
/* Figure out how much larger the mapping should be. */
map_offset = directory->offset - offset;
/* Do the mmap. */
glyphs = mmap (NULL, directory->length + map_offset,
PROT_READ, MAP_PRIVATE, fd, offset);
if (glyphs == MAP_FAILED)
{
fprintf (stderr, "sfnt_map_glyf_table: mmap: %s\n",
strerror (errno));
return NULL;
}
/* An observation is that glyphs tend to be accessed in sequential
order and immediately after the font's glyph table is loaded. */
#ifdef HAVE_POSIX_MADVISE
posix_madvise (glyphs, directory->length,
POSIX_MADV_WILLNEED);
#elif defined HAVE_MADVISE
madvise (glyphs, directory->length, MADV_WILLNEED);
#endif
/* Allocate the glyf table. */
glyf = xmalloc (sizeof *glyf);
glyf->size = directory->length;
glyf->glyphs = (unsigned char *) glyphs + map_offset;
glyf->start = glyphs;
return glyf;
}
/* Unmap the mmap'ed glyf table GLYF, then free its associated data.
Value is 0 upon success, else 1, in which case GLYF is still freed
all the same. */
int
sfnt_unmap_glyf_table (struct sfnt_glyf_table *glyf)
{
int rc;
size_t size;
/* Calculate the size of the mapping. */
size = glyf->size + (glyf->glyphs - glyf->start);
rc = munmap (glyf->start, size);
xfree (glyf);
return rc != 0;
}
#endif /* HAVE_MMAP */
/* Read the simple glyph outline from the glyph GLYPH from the
specified glyf table at the given offset. Set GLYPH->simple to a
non-NULL value upon success, else set it to NULL. */

View file

@ -524,6 +524,10 @@ struct sfnt_glyf_table
/* Pointer to possibly unaligned glyph data. */
unsigned char *glyphs;
/* Pointer to the start of the mapping.
Only initialized if this table was mmapped. */
unsigned char *start;
};
struct sfnt_simple_glyph
@ -951,6 +955,11 @@ extern struct sfnt_loca_table_short *sfnt_read_loca_table_short (PROTOTYPE);
extern struct sfnt_loca_table_long *sfnt_read_loca_table_long (PROTOTYPE);
extern struct sfnt_maxp_table *sfnt_read_maxp_table (PROTOTYPE);
extern struct sfnt_glyf_table *sfnt_read_glyf_table (PROTOTYPE);
#ifdef HAVE_MMAP
extern struct sfnt_glyf_table *sfnt_map_glyf_table (PROTOTYPE);
extern int sfnt_unmap_glyf_table (struct sfnt_glyf_table *);
#endif /* HAVE_MMAP */
#undef PROTOTYPE
extern struct sfnt_glyph *sfnt_read_glyph (sfnt_glyph, struct sfnt_glyf_table *,

View file

@ -1805,6 +1805,11 @@ struct sfnt_font_info
/* Parent font structure. */
struct font font;
#ifdef HAVE_MMAP
/* The next font in this chain. */
struct sfnt_font_info *next;
#endif /* HAVE_MMAP */
/* Various tables required to use the font. */
struct sfnt_cmap_table *cmap;
struct sfnt_hhea_table *hhea;
@ -1842,8 +1847,21 @@ struct sfnt_font_info
/* Graphics state after the execution of the font and control value
programs. */
struct sfnt_graphics_state state;
#ifdef HAVE_MMAP
/* Whether or not the glyph table has been mmapped. */
bool glyf_table_mapped;
#endif /* HAVE_MMAP */
};
#ifdef HAVE_MMAP
/* List of all open fonts. */
static struct sfnt_font_info *open_fonts;
#endif /* HAVE_MMAP */
/* Look up the glyph corresponding to the character C in FONT. Return
0 upon failure, and the glyph otherwise. */
@ -2040,6 +2058,9 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
struct sfnt_font_desc *desc;
Lisp_Object font_object;
int fd, i;
#ifdef HAVE_MMAP
int rc;
#endif /* HAVE_MMAP */
struct sfnt_offset_subtable *subtable;
struct sfnt_cmap_encoding_subtable *subtables;
struct sfnt_cmap_encoding_subtable_data **data;
@ -2096,6 +2117,9 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
font_info->raster_cache.last = &font_info->raster_cache;
font_info->raster_cache_size = 0;
font_info->interpreter = NULL;
#ifdef HAVE_MMAP
font_info->glyf_table_mapped = false;
#endif /* HAVE_MMAP */
/* Open the font. */
fd = emacs_open (desc->path, O_RDONLY, 0);
@ -2145,7 +2169,24 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
/* Read the hhea, maxp, glyf, and head tables. */
font_info->hhea = sfnt_read_hhea_table (fd, subtable);
font_info->maxp = sfnt_read_maxp_table (fd, subtable);
font_info->glyf = sfnt_read_glyf_table (fd, subtable);
#ifdef HAVE_MMAP
/* First try to map the glyf table. If that fails, then read the
glyf table. */
font_info->glyf = sfnt_map_glyf_table (fd, subtable);
/* Next, if this fails, read the glyf table. */
if (!font_info->glyf)
#endif /* HAVE_MMAP */
font_info->glyf = sfnt_read_glyf_table (fd, subtable);
#ifdef HAVE_MMAP
else
font_info->glyf_table_mapped = true;
#endif /* HAVE_MMAP */
font_info->head = sfnt_read_head_table (fd, subtable);
/* If any of those tables couldn't be read, bail. */
@ -2266,6 +2307,12 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
/* Free the offset subtable. */
xfree (subtable);
#ifdef HAVE_MMAP
/* Link the font onto the font table. */
font_info->next = open_fonts;
open_fonts = font_info;
#endif /* HAVE_MMAP */
/* All done. */
unblock_input ();
return font_object;
@ -2281,7 +2328,19 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
bail4:
xfree (font_info->hhea);
xfree (font_info->maxp);
xfree (font_info->glyf);
#ifdef HAVE_MMAP
if (font_info->glyf_table_mapped)
{
rc = sfnt_unmap_glyf_table (font_info->glyf);
if (rc)
emacs_abort ();
}
else
#endif /* HAVE_MMAP */
xfree (font_info->glyf);
xfree (font_info->head);
font_info->hhea = NULL;
font_info->maxp = NULL;
@ -2473,7 +2532,10 @@ sfntfont_text_extents (struct font *font, const unsigned int *code,
void
sfntfont_close (struct font *font)
{
struct sfnt_font_info *info;
struct sfnt_font_info *info, **next;
#ifdef HAVE_MMAP
int rc;
#endif /* HAVE_MMAP */
info = (struct sfnt_font_info *) font;
xfree (info->cmap);
@ -2481,7 +2543,20 @@ sfntfont_close (struct font *font)
xfree (info->maxp);
xfree (info->head);
xfree (info->hmtx);
xfree (info->glyf);
#ifdef HAVE_MMAP
if (info->glyf_table_mapped)
{
rc = sfnt_unmap_glyf_table (info->glyf);
if (rc)
emacs_abort ();
}
else
#endif /* HAVE_MMAP */
xfree (info->glyf);
xfree (info->loca_short);
xfree (info->loca_long);
xfree (info->cmap_data);
@ -2490,6 +2565,16 @@ sfntfont_close (struct font *font)
xfree (info->cvt);
xfree (info->interpreter);
/* Unlink INFO. */
next = &open_fonts;
while (*next && (*next) != info)
next = &(*next)->next;
if (*next)
*next = info->next;
info->next = NULL;
sfntfont_free_outline_cache (&info->outline_cache);
sfntfont_free_raster_cache (&info->raster_cache);
}
@ -2627,6 +2712,34 @@ sfntfont_list_family (struct frame *f)
/* mmap specific stuff. */
#ifdef HAVE_MMAP
/* Return whether or not ADDR lies in a mapped glyph, and bus faults
should be ignored. */
bool
sfntfont_detect_sigbus (void *addr)
{
struct sfnt_font_info *info;
for (info = open_fonts; info; info = info->next)
{
if (info->glyf_table_mapped
&& (unsigned char *) addr >= info->glyf->glyphs
&& (unsigned char *) addr < (info->glyf->glyphs
+ info->glyf->size))
return true;
}
return false;
}
#endif
void
syms_of_sfntfont (void)
{

View file

@ -56,4 +56,13 @@ extern void mark_sfntfont (void);
extern void init_sfntfont_vendor (Lisp_Object, const struct font_driver *,
sfntfont_put_glyph_proc);
/* mmap specific functions. */
#ifdef HAVE_MMAP
extern bool sfntfont_detect_sigbus (void *);
#endif /* HAVE_MMAP */
#endif /* _SFNTFONT_H_ */

View file

@ -138,6 +138,10 @@ int _cdecl _spawnlp (int, const char *, const char *, ...);
#include "android.h"
#endif
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
#include "sfntfont.h"
#endif
/* Declare here, including term.h is problematic on some systems. */
extern void tputs (const char *, int, int (*)(int));
@ -1816,6 +1820,40 @@ handle_arith_signal (int sig)
xsignal0 (Qarith_error);
}
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY && defined HAVE_MMAP
static void
handle_sigbus (int sig, siginfo_t *siginfo, void *arg)
{
/* If this arrives during sfntfont_open, then Emacs may be
screwed. */
if (sfntfont_detect_sigbus (siginfo->si_addr))
return;
handle_fatal_signal (sig);
}
/* Try to set up SIGBUS handling for the sfnt font driver.
Value is 1 upon failure, 0 otherwise. */
static int
init_sigbus (void)
{
struct sigaction sa;
sigfillset (&sa.sa_mask);
sa.sa_sigaction = handle_sigbus;
sa.sa_flags = SA_SIGINFO;
if (sigaction (SIGBUS, &sa, NULL))
return 1;
return 0;
}
#endif
/* This does not work on Android and interferes with the system
tombstone generation. */
@ -2076,7 +2114,10 @@ init_signals (void)
sigaction (SIGEMT, &thread_fatal_action, 0);
#endif
#ifdef SIGBUS
sigaction (SIGBUS, &thread_fatal_action, 0);
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY && defined HAVE_MMAP
if (init_sigbus ())
#endif
sigaction (SIGBUS, &thread_fatal_action, 0);
#endif
#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
if (!init_sigsegv ())