Linux Manual Pages development
 help / color / mirror / Atom feed
* signal(7): why does it say that pthread_mutex_lock() and thread_cond_wait() can fail with EINTR?
@ 2025-01-01 22:20 Arkadiusz Drabczyk
  2025-01-02  0:19 ` Alejandro Colomar
  0 siblings, 1 reply; 6+ messages in thread
From: Arkadiusz Drabczyk @ 2025-01-01 22:20 UTC (permalink / raw)
  To: Alejandro Colomar, mtk.manpages; +Cc: linux-man

In man/man7/signal.7 it says:

> If a blocked call to one of the following interfaces is interrupted
> by a signal handler, then the call is automatically restarted after
> the signal handler returns if the SA_RESTART flag was used;
> otherwise the call fails with the error EINTR:
> (...)
> • pthread_mutex_lock(3), pthread_cond_wait(3), and related APIs.

I don't understand this, in my experiments neither
pthread_mutex_lock() nor pthread_cond_wait() return EINTR even if
signal handler was installed without using SA_RESTART flag. The
underlying futex() call indeed fails with EINTR but it's called again
by both glibc and musl. Additionally both
man/man3/pthread_mutex_lock.3 and man/man3/pthread_cond_wait.3 say
that these functions do not return EINTR.

Is my understanding of the signal.7 wrong or does it need some work?

-- 
Arkadiusz Drabczyk <arkadiusz@drabczyk.org>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: signal(7): why does it say that pthread_mutex_lock() and thread_cond_wait() can fail with EINTR?
  2025-01-01 22:20 signal(7): why does it say that pthread_mutex_lock() and thread_cond_wait() can fail with EINTR? Arkadiusz Drabczyk
@ 2025-01-02  0:19 ` Alejandro Colomar
  2025-01-02  9:53   ` Florian Weimer
  0 siblings, 1 reply; 6+ messages in thread
From: Alejandro Colomar @ 2025-01-02  0:19 UTC (permalink / raw)
  To: Arkadiusz Drabczyk; +Cc: mtk.manpages, linux-man, libc-help

[-- Attachment #1: Type: text/plain, Size: 1435 bytes --]

[CC += libc-help]

Hi Arkadiusz,

On Wed, Jan 01, 2025 at 11:20:26PM +0100, Arkadiusz Drabczyk wrote:
> In man/man7/signal.7 it says:
> 
> > If a blocked call to one of the following interfaces is interrupted
> > by a signal handler, then the call is automatically restarted after
> > the signal handler returns if the SA_RESTART flag was used;
> > otherwise the call fails with the error EINTR:
> > (...)
> > • pthread_mutex_lock(3), pthread_cond_wait(3), and related APIs.
> 
> I don't understand this, in my experiments neither
> pthread_mutex_lock() nor pthread_cond_wait() return EINTR even if
> signal handler was installed without using SA_RESTART flag.

Please show some minimal examples if you can.

> The
> underlying futex() call indeed fails with EINTR but it's called again
> by both glibc and musl.

I've CCed glibc, in case they can comment.  Maybe this behavior changed
at some point in the past?  I don't know.

> Additionally both
> man/man3/pthread_mutex_lock.3 and man/man3/pthread_cond_wait.3 say
> that these functions do not return EINTR.

Those pages are too old.  They were unmaintained in a Debian package,
and we adopted them recently.  I wouldn't trust them blindly.

> Is my understanding of the signal.7 wrong or does it need some work?

It might need some work.  Thanks for the report!


Have a lovely new year!
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: signal(7): why does it say that pthread_mutex_lock() and thread_cond_wait() can fail with EINTR?
  2025-01-02  0:19 ` Alejandro Colomar
@ 2025-01-02  9:53   ` Florian Weimer
  2025-01-02 12:13     ` Alejandro Colomar
  0 siblings, 1 reply; 6+ messages in thread
From: Florian Weimer @ 2025-01-02  9:53 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: Arkadiusz Drabczyk, mtk.manpages, linux-man, libc-help

* Alejandro Colomar:

>> The underlying futex() call indeed fails with EINTR but it's called
>> again by both glibc and musl.
>
> I've CCed glibc, in case they can comment.  Maybe this behavior changed
> at some point in the past?  I don't know.

Maybe in the LinuxThreads implementation.  I think NPTL has handled this
correctly from the beginning.  POSIX bans the EINTR failure condition.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: signal(7): why does it say that pthread_mutex_lock() and thread_cond_wait() can fail with EINTR?
  2025-01-02  9:53   ` Florian Weimer
@ 2025-01-02 12:13     ` Alejandro Colomar
  2025-01-02 19:50       ` Arkadiusz Drabczyk
  0 siblings, 1 reply; 6+ messages in thread
From: Alejandro Colomar @ 2025-01-02 12:13 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Arkadiusz Drabczyk, mtk.manpages, linux-man, libc-help

[-- Attachment #1: Type: text/plain, Size: 699 bytes --]

Hi Florian, Arkadiusz,

On Thu, Jan 02, 2025 at 10:53:57AM +0100, Florian Weimer wrote:
> * Alejandro Colomar:
> 
> >> The underlying futex() call indeed fails with EINTR but it's called
> >> again by both glibc and musl.
> >
> > I've CCed glibc, in case they can comment.  Maybe this behavior changed
> > at some point in the past?  I don't know.
> 
> Maybe in the LinuxThreads implementation.  I think NPTL has handled this
> correctly from the beginning.  POSIX bans the EINTR failure condition.

Thanks!

Arkadiusz, would you do the honours writing a patch?  Should I?

Have a lovely new year!
Alex

> 
> Thanks,
> Florian
> 

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: signal(7): why does it say that pthread_mutex_lock() and thread_cond_wait() can fail with EINTR?
  2025-01-02 12:13     ` Alejandro Colomar
@ 2025-01-02 19:50       ` Arkadiusz Drabczyk
  2025-01-03  1:08         ` Alejandro Colomar
  0 siblings, 1 reply; 6+ messages in thread
From: Arkadiusz Drabczyk @ 2025-01-02 19:50 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: Florian Weimer, mtk.manpages, linux-man, libc-help

On Thu, Jan 02, 2025 at 01:19:38AM +0100, Alejandro Colomar wrote:
> [CC += libc-help]
>
> Hi Arkadiusz,
>
> On Wed, Jan 01, 2025 at 11:20:26PM +0100, Arkadiusz Drabczyk wrote:
> > In man/man7/signal.7 it says:
> >
> > > If a blocked call to one of the following interfaces is interrupted
> > > by a signal handler, then the call is automatically restarted after
> > > the signal handler returns if the SA_RESTART flag was used;
> > > otherwise the call fails with the error EINTR:
> > > (...)
> > > • pthread_mutex_lock(3), pthread_cond_wait(3), and related APIs.
> >
> > I don't understand this, in my experiments neither
> > pthread_mutex_lock() nor pthread_cond_wait() return EINTR even if
> > signal handler was installed without using SA_RESTART flag.
>
> Please show some minimal examples if you can.

Here is the minimal example for pthread_mutex_lock() with all checks:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>

pthread_mutex_t m;

void handle_sigint(int sig)
{
	(void)sig;
	write(STDOUT_FILENO, "SIGINT", 6);
}

void *example_thread(void *arg)
{
	(void)arg;
	int ret = pthread_mutex_lock(&m);
	if (ret) {
		fprintf(stderr, "pthread_mutex_lock: %s\n", strerror(ret));
		return NULL;
	}
	puts("Mutex acquired in thread");
	sleep(3600);
	ret = pthread_mutex_unlock(&m);
	if (ret)
		fprintf(stderr, "pthread_mutex_unlock: %s\n", strerror(ret));

	return NULL;
}

int main(void)
{
	struct sigaction sa;
	pthread_t thread;
	int ret = 0;
	int main_ret = 0;
	int destroy_mutex = 1;

	sa.sa_handler = handle_sigint;
	sa.sa_flags = 0;
	sigemptyset(&sa.sa_mask);

	if (sigaction(SIGINT, &sa, NULL) == -1) {
		perror("sigaction");
		return EXIT_FAILURE;
	}

	pthread_mutex_init(&m, NULL);

	ret = pthread_create(&thread, NULL, example_thread, NULL);
	if (ret) {
		fprintf(stderr, "pthread_create: %s\n", strerror(ret));
		main_ret = ret;
		goto out;
	}

	sleep(3);
	printf("Wait for mutex in main thread, send INT to process %jd now\n", (intmax_t) getpid());
	ret = pthread_mutex_lock(&m);
	if (ret) {
		fprintf(stderr, "pthread_mutex_lock: %s\n", strerror(ret));
		main_ret = ret;
		goto join;
	}

	puts("Got mutex in main thread");

	ret = pthread_mutex_unlock(&m);
	if (ret) {
	   fprintf(stderr, "pthread_mutex_unlock: %s\n", strerror(ret));
	   main_ret = ret;
	   destroy_mutex = 0;
	   goto join;
	}

 join:
	ret = pthread_join(thread, NULL);
	if (ret) {
		fprintf(stderr, "pthread_join: %s\n", strerror(ret));
		return EXIT_FAILURE;
	}

 out:
	if (destroy_mutex) {
		ret = pthread_mutex_destroy(&m);
		if (ret) {
			fprintf(stderr, "pthread_mutex_destroy: %s\n",
				strerror(ret));
			return EXIT_FAILURE;
		}
	}
	return main_ret;
}

> Arkadiusz, would you do the honours writing a patch?  Should I?

I could do that but there is one more problem here - most pthread
manpages mention EINTR only to say that they don't return it except
pthread_cond_init.3:

$ find . -name "*pthread*" -print0 | xargs -0 grep EINTR
./man/man3/pthread_atfork.3:.BR EINTR .
./man/man3/pthread_tryjoin_np.3:.BR EINTR .
./man/man3/pthread_cond_init.3:\fBEINTR\fP
./man/man7/pthreads.7:.BR EINTR .

that says:

> EINTR  pthread_cond_timedwait was interrupted by a signal.

It's hard to say if it ever really worked like that because in
man/man7/pthreads.7 it says that no EINTR has been the requirement
since 2001:

> Most pthreads functions return 0 on success, and an error number on
> failure.  The error numbers that can be returned have the same meaning
> as the error numbers returned in errno by conventional system calls
> and C library functions.  Note that the pthreads functions do not set
> errno.  For each of the pthreads functions that can return an error,
> POSIX.1-2001 specifies that the function can never fail with the error
> EINTR.

Today POSIX still says that pthread_cond_timedwait() cannot return
EINTR
https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_clockwait.html
and in my experiments it really doesn't, both with glibc and musl.

pthread_cond_init.3 has been added in 1998 under linuxthread/
directory, maybe the behavior specified by POSIX was different than
the initial design but OTOH it's quite surprising that no one noticed
the bug for so many years, I wonder how many people still check for
EINTR in pthread_cond_timedwait even though it's not necessary (but
harmless).

So I was thinking that "pthread_mutex_lock(3), pthread_cond_wait(3),
and related APIs." line could be completely removed from signal.7
because there is no pthread API that would return EINTR and EINTR
should be removed from the list of valid error codes in
pthread_cond_init.3. Does it sound good?

-- 
Arkadiusz Drabczyk <arkadiusz@drabczyk.org>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: signal(7): why does it say that pthread_mutex_lock() and thread_cond_wait() can fail with EINTR?
  2025-01-02 19:50       ` Arkadiusz Drabczyk
@ 2025-01-03  1:08         ` Alejandro Colomar
  0 siblings, 0 replies; 6+ messages in thread
From: Alejandro Colomar @ 2025-01-03  1:08 UTC (permalink / raw)
  To: Arkadiusz Drabczyk; +Cc: Florian Weimer, mtk.manpages, linux-man, libc-help

[-- Attachment #1: Type: text/plain, Size: 5293 bytes --]

Hi,

On Thu, Jan 02, 2025 at 08:50:17PM +0100, Arkadiusz Drabczyk wrote:
> Here is the minimal example for pthread_mutex_lock() with all checks:

[...]

Thanks!

> > Arkadiusz, would you do the honours writing a patch?  Should I?
> 
> I could do that but there is one more problem here - most pthread
> manpages mention EINTR only to say that they don't return it except
> pthread_cond_init.3:
> 
> $ find . -name "*pthread*" -print0 | xargs -0 grep EINTR

In this repo, we respect POSIX recommendations.  You can safely pass
filenames to xargs(1) without needing -print0 or -0.  :-)

	$ find man/ -type f | grep pthread | xargs grep EINTR;

> ./man/man3/pthread_atfork.3:.BR EINTR .
> ./man/man3/pthread_tryjoin_np.3:.BR EINTR .
> ./man/man3/pthread_cond_init.3:\fBEINTR\fP
> ./man/man7/pthreads.7:.BR EINTR .
> 
> that says:
> 
> > EINTR  pthread_cond_timedwait was interrupted by a signal.
> 
> It's hard to say if it ever really worked like that because in
> man/man7/pthreads.7 it says that no EINTR has been the requirement
> since 2001:
> 
> > Most pthreads functions return 0 on success, and an error number on
> > failure.  The error numbers that can be returned have the same meaning
> > as the error numbers returned in errno by conventional system calls
> > and C library functions.  Note that the pthreads functions do not set
> > errno.  For each of the pthreads functions that can return an error,
> > POSIX.1-2001 specifies that the function can never fail with the error
> > EINTR.
> 
> Today POSIX still says that pthread_cond_timedwait() cannot return
> EINTR
> https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_clockwait.html
> and in my experiments it really doesn't, both with glibc and musl.
> 
> pthread_cond_init.3 has been added in 1998 under linuxthread/
> directory, maybe the behavior specified by POSIX was different than
> the initial design but OTOH it's quite surprising that no one noticed
> the bug for so many years, I wonder how many people still check for
> EINTR in pthread_cond_timedwait even though it's not necessary (but
> harmless).

The history of that manual page is quite complex.

	$ git log --oneline --graph --abbrev --date=short --format='%h (%ad, %cd; "%s")' --follow -- man/man3/pthread_cond_init.3 | cat
	...
	* ec557d3c5 (2024-11-13, 2024-11-13; "pthread_cond_init.3: tfix")
	...
	* d88513fd7 (2024-06-16, 2024-06-16; "man/, share/mk/: srcfix, and remove corresponding XFAIL exceptions")
	...
	* b841c4f3c (2024-05-19, 2024-05-19; "pthread_*.3: ffix")
	...
	* dcde2f703 (2024-04-26, 2024-05-02; "man/, share/mk/: Move man*/ to man/")
	...
	* ee7b1c770 (2024-02-26, 2024-02-26; "man3/: Say cancelation instead of cancellation")
	...
	* c6d039a3a (2023-10-31, 2023-10-31; "man*/: srcfix (Use .P instead of .PP or .LP)")
	...
	* 8a00cac75 (2023-10-04, 2023-10-04; "pthread_*.3: ffix (semantic newlines)")
	* 74235f157 (2023-10-03, 2023-10-04; "pthread_*.3: ffix (paragraphing)")
	* 13151ec52 (2023-10-03, 2023-10-04; "pthread_*.3: Remove AUTHOR section; add copyright; adapt TH")
	* c1c253d0e (2023-10-04, 2023-10-04; "pthread_cond_init.3, pthread_condattr_init.3, pthread_key_create.3, pthread_mutex_init.3, pthread_mutexattr_setkind_np.3, pthread_once.3: Update the glibc pages with the debian/glibc version of them")
	...
	* a254db8b3 (2023-10-03, 2023-10-04; "pthread_cond_init.3, pthread_condattr_init.3, pthread_key_create.3, pthread_mutex_init.3, pthread_mutexattr_setkind_np.3, pthread_once.3: Import pages from glibc")
	* 87d09778d (2023-10-03, 2023-10-04; "Revert "linuxthreads, linuxthreads_db: Directories removed (preserved in ports repository)."")
	... 
	| * a3db24d46 (2005-07-03, 2023-10-03; "linuxthreads, linuxthreads_db: Directories removed (preserved in ports repository).")
	| * 2988d2724 (2004-12-22, 2023-10-03; "(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.")
	| * f7f73b1ca (2007-07-12, 2023-10-03; "2.5-18.1")
	... 
	| * 869af9b6a (1999-05-23, 2023-10-03; "Correct example.")
	| * 31b1e42d5 (1998-03-11, 2023-10-03; "LinuxThreads library.")
	|/  

(There are a few commits that don't show up there, and I don't know how
 to show them.)

Notice the difference between author dates and commit dates in the
bottom 5 commits.

Those pages were removed in the glibc repository as obsolete in 2005.
Debian imported them into a package, but they weren't maintained for a
long time.  At some point, I realized about their existence, and decided
to import them, with all of their git gistory, into the Linux man-pages
project, to start maintaining them, and eventually de-obsolete them
(which as you can see, hasn't happened yet; I need people like you
 reporting their problems).  I imported them last year.

> So I was thinking that "pthread_mutex_lock(3), pthread_cond_wait(3),
> and related APIs." line could be completely removed from signal.7
> because there is no pthread API that would return EINTR and EINTR
> should be removed from the list of valid error codes in
> pthread_cond_init.3. Does it sound good?

Sounds good.  Please CC Florian and libc-help@ if you send a patch, so
they can review.


Have a lovely night!
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-01-03  1:08 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-01 22:20 signal(7): why does it say that pthread_mutex_lock() and thread_cond_wait() can fail with EINTR? Arkadiusz Drabczyk
2025-01-02  0:19 ` Alejandro Colomar
2025-01-02  9:53   ` Florian Weimer
2025-01-02 12:13     ` Alejandro Colomar
2025-01-02 19:50       ` Arkadiusz Drabczyk
2025-01-03  1:08         ` Alejandro Colomar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox