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 { 97, 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, mem_block: (*trash_list)->data); |
46 | *trash_list = g_slist_delete_link (list: *trash_list, link_: *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 (list: free_list, data: 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 (block_size: 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 (list: free_list, data: 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 (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 (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 (block_size: magazine_probes[j], mem_block: 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 (block_size: magazine_probes[j]); |
120 | if (mem == mps[j]) |
121 | break; /* reallocated previously freed slice */ |
122 | trash = g_slist_prepend (list: trash, data: mem); |
123 | } |
124 | release_trash_list (trash_list: &trash, block_size: 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 (block_size: magazine_probes[j], mem_block: 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 (block_size: magazine_probes[j]); |
146 | if (mem == mps[j]) |
147 | break; /* reallocated previously freed slice */ |
148 | trash = g_slist_prepend (list: trash, data: mem); |
149 | } |
150 | release_trash_list (trash_list: &trash, block_size: 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 (block_size: magazine_probes[j], mem_block: mps[j]); |
163 | release_trash_list (trash_list: &free_list, SAMPLE_SIZE); |
164 | |
165 | return 0; |
166 | } |
167 | |