* 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.
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],
(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)
# 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
#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"
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. */
/* 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
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 *,
/* 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;
/* 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. */
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;
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);
/* 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. */
/* 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;
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;
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);
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);
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);
}
\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
+
+\f
+
void
syms_of_sfntfont (void)
{
extern void init_sfntfont_vendor (Lisp_Object, const struct font_driver *,
sfntfont_put_glyph_proc);
+\f
+/* mmap specific functions. */
+
+#ifdef HAVE_MMAP
+
+extern bool sfntfont_detect_sigbus (void *);
+
+#endif /* HAVE_MMAP */
+
#endif /* _SFNTFONT_H_ */
#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));
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. */
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 ())