Home | History | Annotate | Download | only in tests
      1 /* slice-threadinit.c - test GSlice across g_thread_init
      2  * Copyright (C) 2007 Tim Janik
      3  *
      4  * This work is provided "as is"; redistribution and modification
      5  * in whole or in part, in any medium, physical or electronic is
      6  * permitted without restriction.
      7  *
      8  * This work is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11  *
     12  * In no event shall the authors or contributors be liable for any
     13  * direct, indirect, incidental, special, exemplary, or consequential
     14  * damages (including, but not limited to, procurement of substitute
     15  * goods or services; loss of use, data, or profits; or business
     16  * interruption) however caused and on any theory of liability, whether
     17  * in contract, strict liability, or tort (including negligence or
     18  * otherwise) arising in any way out of the use of this software, even
     19  * if advised of the possibility of such damage.
     20  */
     21 #include <glib.h>
     22 
     23 #define N_PAGES                 (101)                   /* number of pages to sample */
     24 #define SAMPLE_SIZE             (7)
     25 #define PAGE_SIZE               (128)                   /* must be <= minimum GSlice alignment block */
     26 #define MAGAZINE_PROBES         { 81, 265, 347 }        /* block sizes hopefully unused by g_thread_init */
     27 #define MAX_PROBE_TRIALS        (1031)                  /* must be >= maximum magazine size */
     28 
     29 #define ALIGN(size, base)       ((base) * (gsize) (((size) + (base) - 1) / (base)))
     30 
     31 static struct {
     32   void *page;
     33   void *sample;
     34 } pages[N_PAGES] = { { NULL, }, };
     35 
     36 static const guint magazine_probes[] = MAGAZINE_PROBES;
     37 #define N_MAGAZINE_PROBES       G_N_ELEMENTS (magazine_probes)
     38 
     39 static void
     40 release_trash_list (GSList **trash_list,
     41                     gsize    block_size)
     42 {
     43   while (*trash_list)
     44     {
     45       g_slice_free1 (block_size, (*trash_list)->data);
     46       *trash_list = g_slist_delete_link (*trash_list, *trash_list);
     47     }
     48 }
     49 
     50 static GSList *free_list = NULL;
     51 
     52 static gboolean
     53 allocate_from_known_page (void)
     54 {
     55   guint i, j, n_trials = N_PAGES * PAGE_SIZE / SAMPLE_SIZE; /* upper bound */
     56   for (i = 0; i < n_trials; i++)
     57     {
     58       void *b = g_slice_alloc (SAMPLE_SIZE);
     59       void *p = (void*) (PAGE_SIZE * ((gsize) b / PAGE_SIZE));
     60       free_list = g_slist_prepend (free_list, b);
     61       /* find page */
     62       for (j = 0; j < N_PAGES; j++)
     63         if (pages[j].page == p)
     64           return TRUE;
     65     }
     66   return FALSE;
     67 }
     68 
     69 int
     70 main (int   argc,
     71       char *argv[])
     72 {
     73   int j, n_pages = 0;
     74   void *mps[N_MAGAZINE_PROBES];
     75 
     76   /* probe some magazine sizes */
     77   for (j = 0; j < N_MAGAZINE_PROBES; j++)
     78     mps[j] = g_slice_alloc (magazine_probes[j]);
     79   /* mps[*] now contains pointers to allocated slices */
     80 
     81   /* allocate blocks from N_PAGES different pages */
     82   while (n_pages < N_PAGES)
     83     {
     84       void *b = g_slice_alloc (SAMPLE_SIZE);
     85       void *p = (void*) (PAGE_SIZE * ((gsize) b / PAGE_SIZE));
     86       for (j = 0; j < N_PAGES; j++)
     87         if (pages[j].page == p)
     88           break;
     89       if (j < N_PAGES)  /* known page */
     90         free_list = g_slist_prepend (free_list, b);
     91       else              /* new page */
     92         {
     93           j = n_pages++;
     94           pages[j].page = p;
     95           pages[j].sample = b;
     96         }
     97     }
     98   /* release intermediate allocations */
     99   release_trash_list (&free_list, SAMPLE_SIZE);
    100 
    101   /* ensure that we can allocate from known pages */
    102   if (!allocate_from_known_page())
    103     g_error ("failed to allocate from magazine/page cache (before g_thread_init)");
    104   /* release intermediate allocations */
    105   release_trash_list (&free_list, SAMPLE_SIZE);
    106 
    107   /* release magazine probes to be retained */
    108   for (j = 0; j < N_MAGAZINE_PROBES; j++)
    109     g_slice_free1 (magazine_probes[j], mps[j]);
    110   /* mps[*] now contains pointers to releaed slices */
    111 
    112   /* ensure probes were retained */
    113   for (j = 0; j < N_MAGAZINE_PROBES; j++)
    114     {
    115       GSList *trash = NULL;
    116       guint k;
    117       for (k = 0; k < MAX_PROBE_TRIALS; k++)
    118         {
    119           void *mem = g_slice_alloc (magazine_probes[j]);
    120           if (mem == mps[j])
    121             break;      /* reallocated previously freed slice */
    122           trash = g_slist_prepend (trash, mem);
    123         }
    124       release_trash_list (&trash, magazine_probes[j]);
    125       if (k >= MAX_PROBE_TRIALS)        /* failed to reallocate slice */
    126         g_error ("failed to reallocate slice from magazine (before g_thread_init): size=%d", magazine_probes[j]);
    127     }
    128   /* mps[*] now contains pointers to reallocated slices */
    129 
    130   /* release magazine probes to be retained across g_thread_init */
    131   for (j = 0; j < N_MAGAZINE_PROBES; j++)
    132     g_slice_free1 (magazine_probes[j], mps[j]);
    133   /* mps[*] now contains pointers to released slices */
    134 
    135   /* initialize threading (should retain allocator state) */
    136   g_thread_init (NULL);
    137 
    138   /* ensure probes were retained */
    139   for (j = 0; j < N_MAGAZINE_PROBES; j++)
    140     {
    141       GSList *trash = NULL;
    142       guint k;
    143       for (k = 0; k < MAX_PROBE_TRIALS; k++)
    144         {
    145           void *mem = g_slice_alloc (magazine_probes[j]);
    146           if (mem == mps[j])
    147             break;      /* reallocated previously freed slice */
    148           trash = g_slist_prepend (trash, mem);
    149         }
    150       release_trash_list (&trash, magazine_probes[j]);
    151       if (k >= MAX_PROBE_TRIALS)        /* failed to reallocate slice */
    152         g_error ("failed to reallocate slice from magazine (after g_thread_init): size=%d", magazine_probes[j]);
    153     }
    154   /* mps[*] now contains pointers to reallocated slices */
    155 
    156   /* ensure that we can allocate from known pages */
    157   if (!allocate_from_known_page())
    158     g_error ("failed to allocate from magazine/page cache (after g_thread_init)");
    159 
    160   /* some cleanups */
    161   for (j = 0; j < N_MAGAZINE_PROBES; j++)
    162     g_slice_free1 (magazine_probes[j], mps[j]);
    163   release_trash_list (&free_list, SAMPLE_SIZE);
    164 
    165   return 0;
    166 }
    167