1
0
mirror of https://gitlab.gnome.org/GNOME/glib.git synced 2025-08-12 04:04:04 +02:00

gstdio: make g_close() async-signal-safe under certain conditions

g_close() does something useful. It is not trivial to get EINTR handling of
close() right, in a portable manner. g_close() abstracts this.

We should allow glib users to use the function even in async-signal-safe
contexts, at least if the user heeds the caveat about GError and take care
not to fail assertions.

Backport 2.74: Modified to drop documentation changes to g_close() which
document its new async-signal-safe guarantees. They are not public
guarantees until 2.76. Also modified to include moving the code to
ignore `EINTR` from commit d5dc7d266f.
This commit is contained in:
Thomas Haller
2022-10-18 09:07:35 +02:00
committed by Philip Withnall
parent f0bcb7f79c
commit 0cfc5b054a

@@ -1749,8 +1749,9 @@ g_utime (const gchar *filename,
* @fd: A file descriptor * @fd: A file descriptor
* @error: a #GError * @error: a #GError
* *
* This wraps the close() call; in case of error, %errno will be * This wraps the close() call. In case of error, %errno will be
* preserved, but the error will also be stored as a #GError in @error. * preserved, but the error will also be stored as a #GError in @error.
* In case of success, %errno is undefined.
* *
* Besides using #GError, there is another major reason to prefer this * Besides using #GError, there is another major reason to prefer this
* function over the call provided by the system; on Unix, it will * function over the call provided by the system; on Unix, it will
@@ -1766,24 +1767,38 @@ g_close (gint fd,
GError **error) GError **error)
{ {
int res; int res;
/* Important: if @error is NULL, we must not do anything that is
* not async-signal-safe.
*/
res = close (fd); res = close (fd);
if (res == -1)
{
int errsv = errno;
if (errsv == EINTR)
{
/* Just ignore EINTR for now; a retry loop is the wrong thing to do /* Just ignore EINTR for now; a retry loop is the wrong thing to do
* on Linux at least. Anyone who wants to add a conditional check * on Linux at least. Anyone who wants to add a conditional check
* for e.g. HP-UX is welcome to do so later... * for e.g. HP-UX is welcome to do so later...
* *
* https://lwn.net/Articles/576478/
* http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
* https://bugzilla.gnome.org/show_bug.cgi?id=682819 * https://bugzilla.gnome.org/show_bug.cgi?id=682819
* http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
* https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
*/ */
if (G_UNLIKELY (res == -1 && errno == EINTR))
return TRUE; return TRUE;
else if (res == -1) }
if (error)
{ {
int errsv = errno;
g_set_error_literal (error, G_FILE_ERROR, g_set_error_literal (error, G_FILE_ERROR,
g_file_error_from_errno (errsv), g_file_error_from_errno (errsv),
g_strerror (errsv)); g_strerror (errsv));
}
errno = errsv; errno = errsv;
return FALSE; return FALSE;
} }