DKIM-Filter: OpenDKIM Filter v2.11.0 delorie.com 44NI9huK2920119 Authentication-Results: delorie.com; dkim=pass (1024-bit key, unprotected) header.d=cygwin.com header.i=@cygwin.com header.a=rsa-sha256 header.s=default header.b=aRhyrgE6 X-Recipient: archive-cygwin AT delorie DOT com DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4BF533858D38 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cygwin.com; s=default; t=1716487781; bh=nX3sj7s/GL8v219IbZxg8NO2QOjImMBUInVsSdLlLF8=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=aRhyrgE6t6h1ig1djCeq71sTyolFAsIea8+Ke2dDR83n8rcJ+mwQ/K5tlemILnTG6 oSE4mZgDKk8D2ZBq+yZYeN6wpvkBe/m5pPWhwBUfKLcVO2xDWJvxOQ1yzt5n98moml i+hJlt0kHIYtpxruLwCt5xYO4GDqYmV3BjTByrLQ= X-Original-To: cygwin AT cygwin DOT com Delivered-To: cygwin AT cygwin DOT com DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ACE983858D38 ARC-Filter: OpenARC Filter v1.0.0 sourceware.org ACE983858D38 ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1716487754; cv=pass; b=Olyh6ILbNokM0oKVUvkWcpo1Jx6SsN5XIQNH362GY9d1DBwzAOkg0ao68jmvK8e/QhWENjtcp+yVNEYyKb51dvR4AgU0lhpYNi60XdYG1ES0EnQiyBwSZq3tRnCqNIxmIyokFD8eepLPUsq9Od/A4gwRoEB2FnYW+bBLzbLm7sU= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1716487754; c=relaxed/simple; bh=HjYvO0aWR9m0l1NqV1MdjcxkOLzkDkYTc9of+IgkhbA=; h=DKIM-Signature:DKIM-Signature:From:To:Subject:Date:Message-ID: MIME-Version; b=ja4dj5ryPRHJ6k2Tz+uQe4X+Xd3Qe1YhjBoS7L0F237Pc2mzdsxLlDHrJmWLnXthMQVnox1y0LPFDyyUke3mxWMT4fMPe20Wy4yk80Ew/AyYbBiDu5nNlJ7pL7S1vdyoBP3W9jYLiSsrX8Jo76MC8GHgWqxaueRF641/jpwHWCo= ARC-Authentication-Results: i=2; server2.sourceware.org ARC-Seal: i=1; a=rsa-sha256; t=1716487749; cv=none; d=strato.com; s=strato-dkim-0002; b=ldZpfFijx8I6UDG4ZZ2o+YeIBrLqMDVYoagAq/F3K+cA0YcZBr3h5VFMJGsqpKcDPe FkWOhZF0z19G67HnJowGaMMnIXTLLh7naWfgS1/fjlifhGYTMkcUj6mSkBJS64BVF3GM HUjFqYEAdqNKTwxz8buvSKwZd5+h5QQIpdtqfVnilmjvh6/AmbHGj0COSDz3+w6njw5E U7WXXtQm5UU9/cy4X8pcfdVbw0vgUcCC9FeOwJ0SHc1gvHh4coOMe5Y7TpseOK9zbLT1 atXvOtI1pNwOrqeOxLRGVloYMBKt8ah837xfP55vFdSwCewZaY1Art1kCAugquvpH497 HbIQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1716487749; s=strato-dkim-0002; d=strato.com; h=Message-ID:Date:Subject:To:From:Cc:Date:From:Subject:Sender; bh=CqGhwOwMTjoBU1PjD8zAKsVahX1BGOjBe4Y36vJAZM0=; b=qUTalItjuxu7IQK9A2XXn4h+/QunA3yW9zwTbkWLuEZRi4JaAyKWk534mq+Z5HB+An CnIX9YksIpv+6zuqBObNHtKOvy4C1LsIJbIG4BHvmAADl/zpk60AaWk0z2gsiNGHycWk ywjjbEJiJslcaJb7UOFpaFwJQDpLtdmKdu6da6RkNhdgUdk5XwylFlM0rAWe5JSBRuCW uAmX09rbXJXEcGzHvRSr5ZRKrl/InciR/m0MAp0z1+jcz64HvFjDiVK1FBeypPA58deB dPgUjuPaYcE/q/tB3dvP+O7Y1cxaD4Loeyr6+Ka5CrTjgzTeKApvAhN/FMHnb8NYoBf7 3neQ== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo00 X-RZG-AUTH: ":Ln4Re0+Ic/6oZXR1YgKryK8brlshOcZlIWs+iCP5vnk6shH0WWb0LN8XZoH94zq68+3cfpPC26fyUHTfX3hM/lJqGSPH4qu4hA==" To: cygwin AT cygwin DOT com Subject: multithreading broken in Cygwin 3.5.3 Date: Thu, 23 May 2024 20:09:09 +0200 Message-ID: <3631253.RrQHTzY0li@nimes> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart1986693.iJkMF17ckq" Content-Transfer-Encoding: 7Bit X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, KAM_ASCII_DIVIDERS, KAM_NUMSUBJECT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: cygwin AT cygwin DOT com X-Mailman-Version: 2.1.30 List-Id: General Cygwin discussions and problem reports List-Archive: List-Post: List-Help: List-Subscribe: , From: Bruno Haible via Cygwin Reply-To: Bruno Haible Sender: "Cygwin" This is a multi-part message in MIME format. --nextPart1986693.iJkMF17ckq Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Hi, In Cygwin 3.5.3, on different machines, I see 3 Gnulib tests failing by timeout that worked perfectly fine in Cygwin 3.4.6 and older: FAIL: test-call_once2.exe FAIL: test-lock.exe FAIL: test-pthread-once2.exe Find here attached a simplified version of test-pthread-once2.c. Compile and run: $ x86_64-pc-cygwin-gcc -Wall foo.c $ ./a Expected behaviour: Termination within 1 minute. Actual behaviour: Terminates by timeout after 10 minutes. When I change #define ENABLE_DEBUGGING 0 to #define ENABLE_DEBUGGING 1 the test does lots of output and terminates within 20 seconds. Therefore I can't really tell where the problem comes from. But I do see some changes in $ git diff cygwin-3.4.6 cygwin-3.5.3 winsup/cygwin/thread.cc $ git diff cygwin-3.4.6 cygwin-3.5.3 winsup/testsuite/winsup.api/pthread Bruno --nextPart1986693.iJkMF17ckq Content-Disposition: attachment; filename="foo.c" Content-Transfer-Encoding: 7Bit Content-Type: text/x-csrc; charset="UTF-8"; name="foo.c" /* Whether to enable locking. Uncomment this to get a test program without locking, to verify that it crashes. */ #define ENABLE_LOCKING 1 /* Whether to help the scheduler through explicit sched_yield(). Uncomment this to see if the operating system has a fair scheduler. */ #define EXPLICIT_YIELD 1 /* Whether to print debugging messages. */ #define ENABLE_DEBUGGING 0 /* Number of simultaneous threads. */ #define THREAD_COUNT 10 /* Number of operations performed in each thread. This is quite high, because with a smaller count, say 5000, we often get an "OK" result even without ENABLE_LOCKING (on Linux/x86). */ #define REPEAT_COUNT 50000 #include #include #include #include #include #include #include #include #if EXPLICIT_YIELD # include #endif #if ENABLE_DEBUGGING # define dbgprintf printf #else # define dbgprintf if (0) printf #endif #if EXPLICIT_YIELD # define yield() sched_yield () #else # define yield() #endif /* Returns a reference to the current thread as a pointer, for debugging. */ #define pthread_self_pointer() ((void *) (uintptr_t) pthread_self ()) /* ------------------------ Test once-only execution ------------------------ */ /* Test once-only execution by having several threads attempt to grab a once-only task simultaneously (triggered by releasing a read-write lock). */ static pthread_once_t fresh_once = PTHREAD_ONCE_INIT; static int ready[THREAD_COUNT]; static pthread_mutex_t ready_lock[THREAD_COUNT]; #if ENABLE_LOCKING static pthread_rwlock_t fire_signal[REPEAT_COUNT]; #else static volatile int fire_signal_state; #endif static pthread_once_t once_control; static int performed; static pthread_mutex_t performed_lock; static void once_execute (void) { assert (pthread_mutex_lock (&performed_lock) == 0); performed++; assert (pthread_mutex_unlock (&performed_lock) == 0); } static void * once_contender_thread (void *arg) { int id = (int) (intptr_t) arg; int repeat; for (repeat = 0; repeat <= REPEAT_COUNT; repeat++) { /* Tell the main thread that we're ready. */ assert (pthread_mutex_lock (&ready_lock[id]) == 0); ready[id] = 1; assert (pthread_mutex_unlock (&ready_lock[id]) == 0); if (repeat == REPEAT_COUNT) break; dbgprintf ("Contender %p waiting for signal for round %d\n", pthread_self_pointer (), repeat); #if ENABLE_LOCKING /* Wait for the signal to go. */ assert (pthread_rwlock_rdlock (&fire_signal[repeat]) == 0); /* And don't hinder the others (if the scheduler is unfair). */ assert (pthread_rwlock_unlock (&fire_signal[repeat]) == 0); #else /* Wait for the signal to go. */ while (fire_signal_state <= repeat) yield (); #endif dbgprintf ("Contender %p got the signal for round %d\n", pthread_self_pointer (), repeat); /* Contend for execution. */ assert (pthread_once (&once_control, once_execute) == 0); } return NULL; } static void test_once (void) { int i, repeat; pthread_t threads[THREAD_COUNT]; /* Initialize all variables. */ for (i = 0; i < THREAD_COUNT; i++) { pthread_mutexattr_t attr; ready[i] = 0; assert (pthread_mutexattr_init (&attr) == 0); assert (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL) == 0); assert (pthread_mutex_init (&ready_lock[i], &attr) == 0); assert (pthread_mutexattr_destroy (&attr) == 0); } #if ENABLE_LOCKING for (i = 0; i < REPEAT_COUNT; i++) assert (pthread_rwlock_init (&fire_signal[i], NULL) == 0); #else fire_signal_state = 0; #endif #if ENABLE_LOCKING /* Block all fire_signals. */ for (i = REPEAT_COUNT-1; i >= 0; i--) assert (pthread_rwlock_wrlock (&fire_signal[i]) == 0); #endif /* Spawn the threads. */ for (i = 0; i < THREAD_COUNT; i++) assert (pthread_create (&threads[i], NULL, once_contender_thread, (void *) (intptr_t) i) == 0); for (repeat = 0; repeat <= REPEAT_COUNT; repeat++) { /* Wait until every thread is ready. */ dbgprintf ("Main thread before synchronizing for round %d\n", repeat); for (;;) { int ready_count = 0; for (i = 0; i < THREAD_COUNT; i++) { assert (pthread_mutex_lock (&ready_lock[i]) == 0); ready_count += ready[i]; assert (pthread_mutex_unlock (&ready_lock[i]) == 0); } if (ready_count == THREAD_COUNT) break; yield (); } dbgprintf ("Main thread after synchronizing for round %d\n", repeat); if (repeat > 0) { /* Check that exactly one thread executed the once_execute() function. */ if (performed != 1) abort (); } if (repeat == REPEAT_COUNT) break; /* Preparation for the next round: Initialize once_control. */ memcpy (&once_control, &fresh_once, sizeof (pthread_once_t)); /* Preparation for the next round: Reset the performed counter. */ performed = 0; /* Preparation for the next round: Reset the ready flags. */ for (i = 0; i < THREAD_COUNT; i++) { assert (pthread_mutex_lock (&ready_lock[i]) == 0); ready[i] = 0; assert (pthread_mutex_unlock (&ready_lock[i]) == 0); } /* Signal all threads simultaneously. */ dbgprintf ("Main thread giving signal for round %d\n", repeat); #if ENABLE_LOCKING assert (pthread_rwlock_unlock (&fire_signal[repeat]) == 0); #else fire_signal_state = repeat + 1; #endif } /* Wait for the threads to terminate. */ for (i = 0; i < THREAD_COUNT; i++) assert (pthread_join (threads[i], NULL) == 0); } /* -------------------------------------------------------------------------- */ int main () { /* Declare failure if test takes too long, by using default abort caused by SIGALRM. */ int alarm_value = 600; signal (SIGALRM, SIG_DFL); alarm (alarm_value); { pthread_mutexattr_t attr; assert (pthread_mutexattr_init (&attr) == 0); assert (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL) == 0); assert (pthread_mutex_init (&performed_lock, &attr) == 0); assert (pthread_mutexattr_destroy (&attr) == 0); } printf ("Starting test_once ..."); fflush (stdout); test_once (); printf (" OK\n"); fflush (stdout); return 0; } --nextPart1986693.iJkMF17ckq Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline -- Problem reports: https://cygwin.com/problems.html FAQ: https://cygwin.com/faq/ Documentation: https://cygwin.com/docs.html Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple --nextPart1986693.iJkMF17ckq--