Avoid quitting inside a critical section on MS-Windows
authorEli Zaretskii <eliz@gnu.org>
Thu, 23 Feb 2017 16:15:05 +0000 (18:15 +0200)
committerEli Zaretskii <eliz@gnu.org>
Thu, 23 Feb 2017 16:15:05 +0000 (18:15 +0200)
* src/w32uniscribe.c (uniscribe_list_family):
* src/w32font.c (w32font_list_family, w32font_text_extents)
(w32font_list_internal, w32font_match_internal)
(list_all_matching_fonts): Prevent quitting while these functions
cons lists of fonts, to avoid leaving the critical section taken
by the main thread, which will then cause any other thread
attempting to enter the critical section to hang.  (Bug#25279)

src/w32font.c
src/w32uniscribe.c

index eff1a78937a70619f458ecc40e2467b30800415e..37df1bc43c0e0976f47dfb5986b272978563533d 100644 (file)
@@ -285,18 +285,25 @@ static Lisp_Object
 w32font_list_family (struct frame *f)
 {
   Lisp_Object list = Qnil;
+  Lisp_Object prev_quit = Vinhibit_quit;
   LOGFONT font_match_pattern;
   HDC dc;
 
   memset (&font_match_pattern, 0, sizeof (font_match_pattern));
   font_match_pattern.lfCharSet = DEFAULT_CHARSET;
 
+  /* Prevent quitting while EnumFontFamiliesEx runs and conses the
+     list it will return.  That's because get_frame_dc acquires the
+     critical section, so we cannot quit before we release it in
+     release_frame_dc.  */
+  Vinhibit_quit = Qt;
   dc = get_frame_dc (f);
 
   EnumFontFamiliesEx (dc, &font_match_pattern,
                       (FONTENUMPROC) add_font_name_to_list,
                       (LPARAM) &list, 0);
   release_frame_dc (f, dc);
+  Vinhibit_quit = prev_quit;
 
   return list;
 }
@@ -434,6 +441,7 @@ w32font_text_extents (struct font *font, unsigned *code,
   WORD *wcode;
   SIZE size;
   bool first;
+  Lisp_Object prev_quit = Vinhibit_quit;
 
   struct w32font_info *w32_font = (struct w32font_info *) font;
 
@@ -480,6 +488,12 @@ w32font_text_extents (struct font *font, unsigned *code,
                 is updated to pass in a frame.  */
              f = XFRAME (selected_frame);
 
+             /* Prevent quitting while EnumFontFamiliesEx runs and
+                conses the list it will return.  That's because
+                get_frame_dc acquires the critical section, so we
+                cannot quit before we release it in release_frame_dc.  */
+             prev_quit = Vinhibit_quit;
+             Vinhibit_quit = Qt;
              dc = get_frame_dc (f);
              old_font = SelectObject (dc, w32_font->hfont);
            }
@@ -520,6 +534,7 @@ w32font_text_extents (struct font *font, unsigned *code,
          /* Restore state and release DC.  */
          SelectObject (dc, old_font);
          release_frame_dc (f, dc);
+         Vinhibit_quit = prev_quit;
        }
       return;
     }
@@ -556,6 +571,12 @@ w32font_text_extents (struct font *font, unsigned *code,
         frame.  */
       f = XFRAME (selected_frame);
 
+      /* Prevent quitting while EnumFontFamiliesEx runs and conses the
+        list it will return.  That's because get_frame_dc acquires
+        the critical section, so we cannot quit before we release it
+        in release_frame_dc.  */
+      prev_quit = Vinhibit_quit;
+      Vinhibit_quit = Qt;
       dc = get_frame_dc (f);
       old_font = SelectObject (dc, w32_font->hfont);
     }
@@ -586,6 +607,7 @@ w32font_text_extents (struct font *font, unsigned *code,
   /* Restore state and release DC.  */
   SelectObject (dc, old_font);
   release_frame_dc (f, dc);
+  Vinhibit_quit = prev_quit;
 }
 
 /* w32 implementation of draw for font backend.
@@ -812,12 +834,20 @@ w32font_list_internal (struct frame *f, Lisp_Object font_spec,
     }
   else
     {
+      Lisp_Object prev_quit = Vinhibit_quit;
+
+      /* Prevent quitting while EnumFontFamiliesEx runs and conses the
+        list it will return.  That's because get_frame_dc acquires
+        the critical section, so we cannot quit before we release it
+        in release_frame_dc.  */
+      Vinhibit_quit = Qt;
       dc = get_frame_dc (f);
 
       EnumFontFamiliesEx (dc, &match_data.pattern,
                           (FONTENUMPROC) add_font_entity_to_list,
                           (LPARAM) &match_data, 0);
       release_frame_dc (f, dc);
+      Vinhibit_quit = prev_quit;
     }
 
   return match_data.list;
@@ -844,12 +874,19 @@ w32font_match_internal (struct frame *f, Lisp_Object font_spec,
   if (opentype_only)
     match_data.pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
 
+  /* Prevent quitting while EnumFontFamiliesEx runs and conses the
+     list it will return.  That's because get_frame_dc acquires the
+     critical section, so we cannot quit before we release it in
+     release_frame_dc.  */
+  Lisp_Object prev_quit = Vinhibit_quit;
+  Vinhibit_quit = Qt;
   dc = get_frame_dc (f);
 
   EnumFontFamiliesEx (dc, &match_data.pattern,
                       (FONTENUMPROC) add_one_font_entity_to_list,
                       (LPARAM) &match_data, 0);
   release_frame_dc (f, dc);
+  Vinhibit_quit = prev_quit;
 
   return NILP (match_data.list) ? Qnil : XCAR (match_data.list);
 }
@@ -2064,6 +2101,12 @@ list_all_matching_fonts (struct font_callback_data *match_data)
   Lisp_Object families = w32font_list_family (XFRAME (match_data->frame));
   struct frame *f = XFRAME (match_data->frame);
 
+  /* Prevent quitting while EnumFontFamiliesEx runs and conses the
+     list it will return.  That's because get_frame_dc acquires the
+     critical section, so we cannot quit before we release it in
+     release_frame_dc.  */
+  Lisp_Object prev_quit = Vinhibit_quit;
+  Vinhibit_quit = Qt;
   dc = get_frame_dc (f);
 
   while (!NILP (families))
@@ -2091,6 +2134,7 @@ list_all_matching_fonts (struct font_callback_data *match_data)
     }
 
   release_frame_dc (f, dc);
+  Vinhibit_quit = prev_quit;
 }
 
 static Lisp_Object
index 1584d80f20361057799dd28adcf80617cb3bd9ab..e4055638cc4ecd26b3cc057c7e82d41e552c0a6d 100644 (file)
@@ -89,12 +89,19 @@ uniscribe_list_family (struct frame *f)
   /* Limit enumerated fonts to outline fonts to save time.  */
   font_match_pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
 
+  /* Prevent quitting while EnumFontFamiliesEx runs and conses the
+     list it will return.  That's because get_frame_dc acquires the
+     critical section, so we cannot quit before we release it in
+     release_frame_dc.  */
+  Lisp_Object prev_quit = Vinhibit_quit;
+  Vinhibit_quit = Qt;
   dc = get_frame_dc (f);
 
   EnumFontFamiliesEx (dc, &font_match_pattern,
                       (FONTENUMPROC) add_opentype_font_name_to_list,
                       (LPARAM) &list, 0);
   release_frame_dc (f, dc);
+  Vinhibit_quit = prev_quit;
 
   return list;
 }