LCOV - code coverage report
Current view: top level - glib/glib/tests - thread.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 86 91 94.5 %
Date: 2024-04-23 05:16:05 Functions: 13 13 100.0 %
Branches: 10 18 55.6 %

           Branch data     Line data    Source code
       1                 :            : /* Unit tests for GThread
       2                 :            :  * Copyright (C) 2011 Red Hat, Inc
       3                 :            :  * Author: Matthias Clasen
       4                 :            :  *
       5                 :            :  * SPDX-License-Identifier: LicenseRef-old-glib-tests
       6                 :            :  *
       7                 :            :  * This work is provided "as is"; redistribution and modification
       8                 :            :  * in whole or in part, in any medium, physical or electronic is
       9                 :            :  * permitted without restriction.
      10                 :            :  *
      11                 :            :  * This work is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      14                 :            :  *
      15                 :            :  * In no event shall the authors or contributors be liable for any
      16                 :            :  * direct, indirect, incidental, special, exemplary, or consequential
      17                 :            :  * damages (including, but not limited to, procurement of substitute
      18                 :            :  * goods or services; loss of use, data, or profits; or business
      19                 :            :  * interruption) however caused and on any theory of liability, whether
      20                 :            :  * in contract, strict liability, or tort (including negligence or
      21                 :            :  * otherwise) arising in any way out of the use of this software, even
      22                 :            :  * if advised of the possibility of such damage.
      23                 :            :  */
      24                 :            : 
      25                 :            : #include <config.h>
      26                 :            : #include <errno.h>
      27                 :            : 
      28                 :            : #ifdef HAVE_SYS_TIME_H
      29                 :            : #include <sys/time.h>
      30                 :            : #endif
      31                 :            : #include <sys/types.h>
      32                 :            : #ifdef HAVE_SYS_PRCTL_H
      33                 :            : #include <sys/prctl.h>
      34                 :            : #endif
      35                 :            : 
      36                 :            : #include <glib.h>
      37                 :            : 
      38                 :            : #include "glib/glib-private.h"
      39                 :            : 
      40                 :            : #ifdef G_OS_UNIX
      41                 :            : #include <unistd.h>
      42                 :            : #include <sys/resource.h>
      43                 :            : #endif
      44                 :            : 
      45                 :            : #ifdef THREADS_POSIX
      46                 :            : #include <pthread.h>
      47                 :            : #endif
      48                 :            : 
      49                 :            : static gpointer
      50                 :          1 : thread1_func (gpointer data)
      51                 :            : {
      52                 :          1 :   g_thread_exit (GINT_TO_POINTER (1));
      53                 :            : 
      54                 :            :   g_assert_not_reached ();
      55                 :            : 
      56                 :            :   return NULL;
      57                 :            : }
      58                 :            : 
      59                 :            : /* test that g_thread_exit() works */
      60                 :            : static void
      61                 :          1 : test_thread1 (void)
      62                 :            : {
      63                 :            :   gpointer result;
      64                 :            :   GThread *thread;
      65                 :          1 :   GError *error = NULL;
      66                 :            : 
      67                 :          1 :   thread = g_thread_try_new ("test", thread1_func, NULL, &error);
      68                 :          1 :   g_assert_no_error (error);
      69                 :            : 
      70                 :          1 :   result = g_thread_join (thread);
      71                 :            : 
      72                 :          1 :   g_assert_cmpint (GPOINTER_TO_INT (result), ==, 1);
      73                 :          1 : }
      74                 :            : 
      75                 :            : static gpointer
      76                 :          1 : thread2_func (gpointer data)
      77                 :            : {
      78                 :          1 :   return g_thread_self ();
      79                 :            : }
      80                 :            : 
      81                 :            : /* test that g_thread_self() works */
      82                 :            : static void
      83                 :          1 : test_thread2 (void)
      84                 :            : {
      85                 :            :   gpointer result;
      86                 :            :   GThread *thread;
      87                 :            : 
      88                 :          1 :   thread = g_thread_new ("test", thread2_func, NULL);
      89                 :            : 
      90                 :          1 :   g_assert (g_thread_self () != thread);
      91                 :            : 
      92                 :          1 :   result = g_thread_join (thread);
      93                 :            : 
      94                 :          1 :   g_assert (result == thread);
      95                 :          1 : }
      96                 :            : 
      97                 :            : static gpointer
      98                 :          4 : thread3_func (gpointer data)
      99                 :            : {
     100                 :          4 :   GThread *peer = data;
     101                 :            :   gint retval;
     102                 :            : 
     103                 :          4 :   retval = 3;
     104                 :            : 
     105         [ +  + ]:          4 :   if (peer)
     106                 :            :     {
     107                 :            :       gpointer result;
     108                 :            : 
     109                 :          2 :       result = g_thread_join (peer);
     110                 :            : 
     111                 :          2 :       retval += GPOINTER_TO_INT (result);
     112                 :            :     }
     113                 :            : 
     114                 :          4 :   return GINT_TO_POINTER (retval);
     115                 :            : }
     116                 :            : 
     117                 :            : /* test that g_thread_join() works across peers */
     118                 :            : static void
     119                 :          1 : test_thread3 (void)
     120                 :            : {
     121                 :            :   gpointer result;
     122                 :            :   GThread *thread1, *thread2, *thread3;
     123                 :            : 
     124                 :          1 :   thread1 = g_thread_new ("a", thread3_func, NULL);
     125                 :          1 :   thread2 = g_thread_new ("b", thread3_func, thread1);
     126                 :          1 :   thread3 = g_thread_new ("c", thread3_func, thread2);
     127                 :            : 
     128                 :          1 :   result = g_thread_join (thread3);
     129                 :            : 
     130                 :          1 :   g_assert_cmpint (GPOINTER_TO_INT(result), ==, 9);
     131                 :          1 : }
     132                 :            : 
     133                 :            : /* test that thread creation fails as expected,
     134                 :            :  * by setting RLIMIT_NPROC ridiculously low
     135                 :            :  */
     136                 :            : static void
     137                 :          1 : test_thread4 (void)
     138                 :            : {
     139                 :            : #ifdef _GLIB_ADDRESS_SANITIZER
     140                 :            :   g_test_incomplete ("FIXME: Leaks a GSystemThread's name, see glib#2308");
     141                 :            : #elif defined(HAVE_PRLIMIT)
     142                 :            :   struct rlimit ol, nl;
     143                 :            :   GThread *thread;
     144                 :            :   GError *error;
     145                 :            : 
     146                 :          1 :   getrlimit (RLIMIT_NPROC, &nl);
     147                 :          1 :   nl.rlim_cur = 1;
     148                 :            : 
     149         [ -  + ]:          1 :   if (prlimit (getpid (), RLIMIT_NPROC, &nl, &ol) != 0)
     150                 :          0 :     g_error ("setting RLIMIT_NPROC to {cur=%ld,max=%ld} failed: %s",
     151                 :            :              (long) nl.rlim_cur, (long) nl.rlim_max, g_strerror (errno));
     152                 :            : 
     153                 :          1 :   error = NULL;
     154                 :          1 :   thread = g_thread_try_new ("a", thread1_func, NULL, &error);
     155                 :            : 
     156         [ -  + ]:          1 :   if (thread != NULL)
     157                 :            :     {
     158                 :            :       gpointer result;
     159                 :            : 
     160                 :            :       /* Privileged processes might be able to create new threads even
     161                 :            :        * though the rlimit is too low. There isn't much we can do about
     162                 :            :        * this; we just can't test this failure mode in this situation. */
     163                 :          0 :       g_test_skip ("Unable to test g_thread_try_new() failing with EAGAIN "
     164                 :            :                    "while privileged (CAP_SYS_RESOURCE, CAP_SYS_ADMIN or "
     165                 :            :                    "euid 0?)");
     166                 :          0 :       result = g_thread_join (thread);
     167                 :          0 :       g_assert_cmpint (GPOINTER_TO_INT (result), ==, 1);
     168                 :            :     }
     169                 :            :   else
     170                 :            :     {
     171                 :          1 :       g_assert (thread == NULL);
     172                 :          1 :       g_assert_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN);
     173                 :          1 :       g_error_free (error);
     174                 :            :     }
     175                 :            : 
     176         [ -  + ]:          1 :   if (prlimit (getpid (), RLIMIT_NPROC, &ol, NULL) != 0)
     177                 :          0 :     g_error ("resetting RLIMIT_NPROC failed: %s", g_strerror (errno));
     178                 :            : #endif
     179                 :          1 : }
     180                 :            : 
     181                 :            : static void
     182                 :          1 : test_thread5 (void)
     183                 :            : {
     184                 :            :   GThread *thread;
     185                 :            : 
     186                 :          1 :   thread = g_thread_new ("a", thread3_func, NULL);
     187                 :          1 :   g_thread_ref (thread);
     188                 :          1 :   g_thread_join (thread);
     189                 :          1 :   g_thread_unref (thread);
     190                 :          1 : }
     191                 :            : 
     192                 :            : static gpointer
     193                 :          1 : thread6_func (gpointer data)
     194                 :            : {
     195                 :            : #if defined (HAVE_PTHREAD_SETNAME_NP_WITH_TID) && defined (HAVE_PTHREAD_GETNAME_NP)
     196                 :            :   char name[16];
     197                 :            : 
     198                 :          1 :   pthread_getname_np (pthread_self(), name, 16);
     199                 :            : 
     200                 :          1 :   g_assert_cmpstr (name, ==, data);
     201                 :            : #endif
     202                 :            : 
     203                 :          1 :   return NULL;
     204                 :            : }
     205                 :            : 
     206                 :            : static void
     207                 :          1 : test_thread6 (void)
     208                 :            : {
     209                 :            :   GThread *thread;
     210                 :            : 
     211                 :          1 :   thread = g_thread_new ("abc", thread6_func, "abc");
     212                 :          1 :   g_thread_join (thread);
     213                 :          1 : }
     214                 :            : 
     215                 :            : #if defined(_SC_NPROCESSORS_ONLN) && defined(THREADS_POSIX) && defined(HAVE_PTHREAD_GETAFFINITY_NP)
     216                 :            : static gpointer
     217                 :          1 : thread7_func (gpointer data)
     218                 :            : {
     219                 :          1 :   int idx = 0, err;
     220                 :          1 :   int ncores = sysconf (_SC_NPROCESSORS_ONLN);
     221                 :            : 
     222                 :            :   cpu_set_t old_mask, new_mask;
     223                 :            : 
     224                 :          1 :   err = pthread_getaffinity_np (pthread_self (), sizeof (old_mask), &old_mask);
     225                 :          1 :   CPU_ZERO (&new_mask);
     226                 :          1 :   g_assert_cmpint (err, ==, 0);
     227                 :            : 
     228         [ +  - ]:          1 :   for (idx = 0; idx < ncores; ++idx)
     229   [ +  -  +  -  :          1 :     if (CPU_ISSET (idx, &old_mask))
                   +  - ]
     230                 :            :       {
     231         [ +  - ]:          1 :         CPU_SET (idx, &new_mask);
     232                 :          1 :         break;
     233                 :            :       }
     234                 :            : 
     235                 :          1 :   err = pthread_setaffinity_np (pthread_self (), sizeof (new_mask), &new_mask);
     236                 :          1 :   g_assert_cmpint (err, ==, 0);
     237                 :            : 
     238                 :          1 :   int af_count = g_get_num_processors ();
     239                 :          1 :   return GINT_TO_POINTER (af_count);
     240                 :            : }
     241                 :            : #endif
     242                 :            : 
     243                 :            : static void
     244                 :          1 : test_thread7 (void)
     245                 :            : {
     246                 :            : #if defined(_SC_NPROCESSORS_ONLN) && defined(THREADS_POSIX) && defined(HAVE_PTHREAD_GETAFFINITY_NP)
     247                 :          1 :   GThread *thread = g_thread_new ("mask", thread7_func, NULL);
     248                 :          1 :   gpointer result = g_thread_join (thread);
     249                 :            : 
     250                 :          1 :   g_assert_cmpint (GPOINTER_TO_INT (result), ==, 1);
     251                 :            : #else
     252                 :            :   g_test_skip ("Skipping because pthread_getaffinity_np() is not available");
     253                 :            : #endif
     254                 :          1 : }
     255                 :            : 
     256                 :            : int
     257                 :          1 : main (int argc, char *argv[])
     258                 :            : {
     259                 :          1 :   g_test_init (&argc, &argv, NULL);
     260                 :            : 
     261                 :          1 :   g_test_add_func ("/thread/thread1", test_thread1);
     262                 :          1 :   g_test_add_func ("/thread/thread2", test_thread2);
     263                 :          1 :   g_test_add_func ("/thread/thread3", test_thread3);
     264                 :          1 :   g_test_add_func ("/thread/thread4", test_thread4);
     265                 :          1 :   g_test_add_func ("/thread/thread5", test_thread5);
     266                 :          1 :   g_test_add_func ("/thread/thread6", test_thread6);
     267                 :          1 :   g_test_add_func ("/thread/thread7", test_thread7);
     268                 :            : 
     269                 :          1 :   return g_test_run ();
     270                 :            : }

Generated by: LCOV version 1.14