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