/** * @see free_tmpfiles * @see tmpfiles * */ const char * tmpfile_name (void) { /* If this is the first time that this routine is run, set up the list and add the destructors to the cleanup functions. */ if (tmpfiles == NULL) { /** @note @parblock Incorperate GL_LINKED_LIST's feature to make all actions on it signal safe. This is turned on in configure.ac by invoking: @code AC_DEFINE([SIGNAL_SAFE_LIST], [1], [Define if lists must be signal-safe.]) @endcode Thus this can be safely cleaned up while catching a fatal signal. @endparblock */ tmpfiles = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, NULL, 1); /* Register the free_tmpfiles cleanup function so that it is called when the program exits and whenever the program recieves a fatal signal. */ atexit (free_tmpfiles); at_fatal_signal (free_tmpfiles); } /* Determine the name of the temporary file. */ char *out = xstrdup ("compilerXXXXXX"); int fd = gen_tempname (out, 0, 0, GT_FILE); if (fd < 0) error (1, errno, _("FATAL: failed to create temporary file")); else if (close (fd)) error (1, errno, _("FATAL: failed to close the temporary file")); /* Add the entry to the list of temporary files. */ gl_list_add_last (tmpfiles, out); return out; }
/* Register a subprocess as being a slave process. This means that the subprocess will be terminated when its creator receives a catchable fatal signal or exits normally. Registration ends when wait_subprocess() notices that the subprocess has exited. */ void register_slave_subprocess (pid_t child) { static bool cleanup_slaves_registered = false; if (!cleanup_slaves_registered) { atexit (cleanup_slaves); at_fatal_signal (cleanup_slaves); cleanup_slaves_registered = true; } /* Try to store the new slave in an unused entry of the slaves array. */ { slaves_entry_t *s = slaves; slaves_entry_t *s_end = s + slaves_count; for (; s < s_end; s++) if (!s->used) { /* The two uses of 'volatile' in the slaves_entry_t type above (and ISO C 99 section 5.1.2.3.(5)) ensure that we mark the entry as used only after the child pid has been written to the memory location s->child. */ s->child = child; s->used = 1; return; } } if (slaves_count == slaves_allocated) { /* Extend the slaves array. Note that we cannot use xrealloc(), because then the cleanup_slaves() function could access an already deallocated array. */ slaves_entry_t *old_slaves = slaves; size_t new_slaves_allocated = 2 * slaves_allocated; slaves_entry_t *new_slaves = (slaves_entry_t *) malloc (new_slaves_allocated * sizeof (slaves_entry_t)); if (new_slaves == NULL) { /* xalloc_die() will call exit() which will invoke cleanup_slaves(). Additionally we need to kill child, because it's not yet among the slaves list. */ kill (child, TERMINATOR); xalloc_die (); } memcpy (new_slaves, old_slaves, slaves_allocated * sizeof (slaves_entry_t)); slaves = new_slaves; slaves_allocated = new_slaves_allocated; /* Now we can free the old slaves array. */ if (old_slaves != static_slaves) free (old_slaves); } /* The three uses of 'volatile' in the types above (and ISO C 99 section 5.1.2.3.(5)) ensure that we increment the slaves_count only after the new slave and its 'used' bit have been written to the memory locations that make up slaves[slaves_count]. */ slaves[slaves_count].child = child; slaves[slaves_count].used = 1; slaves_count++; }