GC_INNER void GC_dirty_init(void)
  {
#   if !defined(MSWIN32) && !defined(MSWINCE)
      struct sigaction act, oldact;
      act.sa_flags = SA_RESTART | SA_SIGINFO;
      act.sa_sigaction = GC_write_fault_handler;
      (void)sigemptyset(&act.sa_mask);
#     if defined(THREADS) && !defined(GC_OPENBSD_UTHREADS) \
         && !defined(GC_WIN32_THREADS) && !defined(NACL)
        /* Arrange to postpone the signal while we are in a write fault */
        /* handler.  This effectively makes the handler atomic w.r.t.   */
        /* stopping the world for GC.                                   */
        (void)sigaddset(&act.sa_mask, GC_get_suspend_signal());
#     endif
#   endif /* !MSWIN32 */
    GC_VERBOSE_LOG_PRINTF(
                "Initializing mprotect virtual dirty bit implementation\n");
    GC_dirty_maintained = TRUE;
    if (GC_page_size % HBLKSIZE != 0) {
        ABORT("Page size not multiple of HBLKSIZE");
    }
#   if !defined(MSWIN32) && !defined(MSWINCE)
      /* act.sa_restorer is deprecated and should not be initialized. */
#     if defined(GC_IRIX_THREADS)
        sigaction(SIGSEGV, 0, &oldact);
        sigaction(SIGSEGV, &act, 0);
#     else
        {
          int res = sigaction(SIGSEGV, &act, &oldact);
          if (res != 0) ABORT("Sigaction failed");
        }
#     endif
      if (oldact.sa_flags & SA_SIGINFO) {
        GC_old_segv_handler = oldact.sa_sigaction;
        GC_old_segv_handler_used_si = TRUE;
      } else {
        GC_old_segv_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
        GC_old_segv_handler_used_si = FALSE;
      }
      if (GC_old_segv_handler == (SIG_HNDLR_PTR)SIG_IGN) {
        WARN("Previously ignored segmentation violation!?\n", 0);
        GC_old_segv_handler = (SIG_HNDLR_PTR)SIG_DFL;
      }
      if (GC_old_segv_handler != (SIG_HNDLR_PTR)SIG_DFL) {
        GC_VERBOSE_LOG_PRINTF("Replaced other SIGSEGV handler\n");
      }
#   if defined(HPUX) || defined(LINUX) || defined(HURD) \
       || (defined(FREEBSD) && defined(SUNOS5SIGS))
      sigaction(SIGBUS, &act, &oldact);
      if ((oldact.sa_flags & SA_SIGINFO) != 0) {
        GC_old_bus_handler = oldact.sa_sigaction;
#       if !defined(LINUX)
          GC_old_bus_handler_used_si = TRUE;
#       endif
      } else {
        GC_old_bus_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
#       if !defined(LINUX)
          GC_old_bus_handler_used_si = FALSE;
#       endif
      }
      if (GC_old_bus_handler == (SIG_HNDLR_PTR)SIG_IGN) {
        WARN("Previously ignored bus error!?\n", 0);
#       if !defined(LINUX)
          GC_old_bus_handler = (SIG_HNDLR_PTR)SIG_DFL;
#       else
          /* GC_old_bus_handler is not used by GC_write_fault_handler.  */
#       endif
      } else if (GC_old_bus_handler != (SIG_HNDLR_PTR)SIG_DFL) {
          GC_VERBOSE_LOG_PRINTF("Replaced other SIGBUS handler\n");
      }
#   endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
#   endif /* ! MS windows */
#   if defined(GWW_VDB)
      if (GC_gww_dirty_init())
        return;
#   endif
#   if defined(MSWIN32)
      GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
      if (GC_old_segv_handler != NULL) {
        GC_COND_LOG_PRINTF("Replaced other UnhandledExceptionFilter\n");
      } else {
          GC_old_segv_handler = SIG_DFL;
      }
#   elif defined(MSWINCE)
      /* MPROTECT_VDB is unsupported for WinCE at present.      */
      /* FIXME: implement it (if possible). */
#   endif
  }