Fri Mar 6 11:49:31 2015 UTC ()
XXX: Use only a single thread. We seem to have a bug in our threading code
that causes us to hang in the ksem code if we use more than one.


(christos)
diff -r1.10 -r1.11 src/external/cddl/osnet/dist/tools/ctf/cvt/ctfmerge.c

cvs diff -r1.10 -r1.11 src/external/cddl/osnet/dist/tools/ctf/cvt/ctfmerge.c (switch to unified diff)

--- src/external/cddl/osnet/dist/tools/ctf/cvt/ctfmerge.c 2015/02/07 20:30:03 1.10
+++ src/external/cddl/osnet/dist/tools/ctf/cvt/ctfmerge.c 2015/03/06 11:49:30 1.11
@@ -1,1043 +1,1048 @@ @@ -1,1043 +1,1048 @@
1/* 1/*
2 * CDDL HEADER START 2 * CDDL HEADER START
3 * 3 *
4 * The contents of this file are subject to the terms of the 4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License"). 5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License. 6 * You may not use this file except in compliance with the License.
7 * 7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing. 9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions 10 * See the License for the specific language governing permissions
11 * and limitations under the License. 11 * and limitations under the License.
12 * 12 *
13 * When distributing Covered Code, include this CDDL HEADER in each 13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the 15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner] 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 * 18 *
19 * CDDL HEADER END 19 * CDDL HEADER END
20 */ 20 */
21/* 21/*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms. 23 * Use is subject to license terms.
24 */ 24 */
25 25
26#pragma ident "%Z%%M% %I% %E% SMI" 26#pragma ident "%Z%%M% %I% %E% SMI"
27 27
28/* 28/*
29 * Given several files containing CTF data, merge and uniquify that data into 29 * Given several files containing CTF data, merge and uniquify that data into
30 * a single CTF section in an output file. 30 * a single CTF section in an output file.
31 * 31 *
32 * Merges can proceed independently. As such, we perform the merges in parallel 32 * Merges can proceed independently. As such, we perform the merges in parallel
33 * using a worker thread model. A given glob of CTF data (either all of the CTF 33 * using a worker thread model. A given glob of CTF data (either all of the CTF
34 * data from a single input file, or the result of one or more merges) can only 34 * data from a single input file, or the result of one or more merges) can only
35 * be involved in a single merge at any given time, so the process decreases in 35 * be involved in a single merge at any given time, so the process decreases in
36 * parallelism, especially towards the end, as more and more files are 36 * parallelism, especially towards the end, as more and more files are
37 * consolidated, finally resulting in a single merge of two large CTF graphs. 37 * consolidated, finally resulting in a single merge of two large CTF graphs.
38 * Unfortunately, the last merge is also the slowest, as the two graphs being 38 * Unfortunately, the last merge is also the slowest, as the two graphs being
39 * merged are each the product of merges of half of the input files. 39 * merged are each the product of merges of half of the input files.
40 * 40 *
41 * The algorithm consists of two phases, described in detail below. The first 41 * The algorithm consists of two phases, described in detail below. The first
42 * phase entails the merging of CTF data in groups of eight. The second phase 42 * phase entails the merging of CTF data in groups of eight. The second phase
43 * takes the results of Phase I, and merges them two at a time. This disparity 43 * takes the results of Phase I, and merges them two at a time. This disparity
44 * is due to an observation that the merge time increases at least quadratically 44 * is due to an observation that the merge time increases at least quadratically
45 * with the size of the CTF data being merged. As such, merges of CTF graphs 45 * with the size of the CTF data being merged. As such, merges of CTF graphs
46 * newly read from input files are much faster than merges of CTF graphs that 46 * newly read from input files are much faster than merges of CTF graphs that
47 * are themselves the results of prior merges. 47 * are themselves the results of prior merges.
48 * 48 *
49 * A further complication is the need to ensure the repeatability of CTF merges. 49 * A further complication is the need to ensure the repeatability of CTF merges.
50 * That is, a merge should produce the same output every time, given the same 50 * That is, a merge should produce the same output every time, given the same
51 * input. In both phases, this consistency requirement is met by imposing an 51 * input. In both phases, this consistency requirement is met by imposing an
52 * ordering on the merge process, thus ensuring that a given set of input files 52 * ordering on the merge process, thus ensuring that a given set of input files
53 * are merged in the same order every time. 53 * are merged in the same order every time.
54 * 54 *
55 * Phase I 55 * Phase I
56 * 56 *
57 * The main thread reads the input files one by one, transforming the CTF 57 * The main thread reads the input files one by one, transforming the CTF
58 * data they contain into tdata structures. When a given file has been read 58 * data they contain into tdata structures. When a given file has been read
59 * and parsed, it is placed on the work queue for retrieval by worker threads. 59 * and parsed, it is placed on the work queue for retrieval by worker threads.
60 * 60 *
61 * Central to Phase I is the Work In Progress (wip) array, which is used to 61 * Central to Phase I is the Work In Progress (wip) array, which is used to
62 * merge batches of files in a predictable order. Files are read by the main 62 * merge batches of files in a predictable order. Files are read by the main
63 * thread, and are merged into wip array elements in round-robin order. When 63 * thread, and are merged into wip array elements in round-robin order. When
64 * the number of files merged into a given array slot equals the batch size, 64 * the number of files merged into a given array slot equals the batch size,
65 * the merged CTF graph in that array is added to the done slot in order by 65 * the merged CTF graph in that array is added to the done slot in order by
66 * array slot. 66 * array slot.
67 * 67 *
68 * For example, consider a case where we have five input files, a batch size 68 * For example, consider a case where we have five input files, a batch size
69 * of two, a wip array size of two, and two worker threads (T1 and T2). 69 * of two, a wip array size of two, and two worker threads (T1 and T2).
70 * 70 *
71 * 1. The wip array elements are assigned initial batch numbers 0 and 1. 71 * 1. The wip array elements are assigned initial batch numbers 0 and 1.
72 * 2. T1 reads an input file from the input queue (wq_queue). This is the 72 * 2. T1 reads an input file from the input queue (wq_queue). This is the
73 * first input file, so it is placed into wip[0]. The second file is 73 * first input file, so it is placed into wip[0]. The second file is
74 * similarly read and placed into wip[1]. The wip array slots now contain 74 * similarly read and placed into wip[1]. The wip array slots now contain
75 * one file each (wip_nmerged == 1). 75 * one file each (wip_nmerged == 1).
76 * 3. T1 reads the third input file, which it merges into wip[0]. The 76 * 3. T1 reads the third input file, which it merges into wip[0]. The
77 * number of files in wip[0] is equal to the batch size. 77 * number of files in wip[0] is equal to the batch size.
78 * 4. T2 reads the fourth input file, which it merges into wip[1]. wip[1] 78 * 4. T2 reads the fourth input file, which it merges into wip[1]. wip[1]
79 * is now full too. 79 * is now full too.
80 * 5. T2 attempts to place the contents of wip[1] on the done queue 80 * 5. T2 attempts to place the contents of wip[1] on the done queue
81 * (wq_done_queue), but it can't, since the batch ID for wip[1] is 1. 81 * (wq_done_queue), but it can't, since the batch ID for wip[1] is 1.
82 * Batch 0 needs to be on the done queue before batch 1 can be added, so 82 * Batch 0 needs to be on the done queue before batch 1 can be added, so
83 * T2 blocks on wip[1]'s cv. 83 * T2 blocks on wip[1]'s cv.
84 * 6. T1 attempts to place the contents of wip[0] on the done queue, and 84 * 6. T1 attempts to place the contents of wip[0] on the done queue, and
85 * succeeds, updating wq_lastdonebatch to 0. It clears wip[0], and sets 85 * succeeds, updating wq_lastdonebatch to 0. It clears wip[0], and sets
86 * its batch ID to 2. T1 then signals wip[1]'s cv to awaken T2. 86 * its batch ID to 2. T1 then signals wip[1]'s cv to awaken T2.
87 * 7. T2 wakes up, notices that wq_lastdonebatch is 0, which means that 87 * 7. T2 wakes up, notices that wq_lastdonebatch is 0, which means that
88 * batch 1 can now be added. It adds wip[1] to the done queue, clears 88 * batch 1 can now be added. It adds wip[1] to the done queue, clears
89 * wip[1], and sets its batch ID to 3. It signals wip[0]'s cv, and 89 * wip[1], and sets its batch ID to 3. It signals wip[0]'s cv, and
90 * restarts. 90 * restarts.
91 * 91 *
92 * The above process continues until all input files have been consumed. At 92 * The above process continues until all input files have been consumed. At
93 * this point, a pair of barriers are used to allow a single thread to move 93 * this point, a pair of barriers are used to allow a single thread to move
94 * any partial batches from the wip array to the done array in batch ID order. 94 * any partial batches from the wip array to the done array in batch ID order.
95 * When this is complete, wq_done_queue is moved to wq_queue, and Phase II 95 * When this is complete, wq_done_queue is moved to wq_queue, and Phase II
96 * begins. 96 * begins.
97 * 97 *
98 * Locking Semantics (Phase I) 98 * Locking Semantics (Phase I)
99 * 99 *
100 * The input queue (wq_queue) and the done queue (wq_done_queue) are 100 * The input queue (wq_queue) and the done queue (wq_done_queue) are
101 * protected by separate mutexes - wq_queue_lock and wq_done_queue. wip 101 * protected by separate mutexes - wq_queue_lock and wq_done_queue. wip
102 * array slots are protected by their own mutexes, which must be grabbed 102 * array slots are protected by their own mutexes, which must be grabbed
103 * before releasing the input queue lock. The wip array lock is dropped 103 * before releasing the input queue lock. The wip array lock is dropped
104 * when the thread restarts the loop. If the array slot was full, the 104 * when the thread restarts the loop. If the array slot was full, the
105 * array lock will be held while the slot contents are added to the done 105 * array lock will be held while the slot contents are added to the done
106 * queue. The done queue lock is used to protect the wip slot cv's. 106 * queue. The done queue lock is used to protect the wip slot cv's.
107 * 107 *
108 * The pow number is protected by the queue lock. The master batch ID 108 * The pow number is protected by the queue lock. The master batch ID
109 * and last completed batch (wq_lastdonebatch) counters are protected *in 109 * and last completed batch (wq_lastdonebatch) counters are protected *in
110 * Phase I* by the done queue lock. 110 * Phase I* by the done queue lock.
111 * 111 *
112 * Phase II 112 * Phase II
113 * 113 *
114 * When Phase II begins, the queue consists of the merged batches from the 114 * When Phase II begins, the queue consists of the merged batches from the
115 * first phase. Assume we have five batches: 115 * first phase. Assume we have five batches:
116 * 116 *
117 * Q: a b c d e 117 * Q: a b c d e
118 * 118 *
119 * Using the same batch ID mechanism we used in Phase I, but without the wip 119 * Using the same batch ID mechanism we used in Phase I, but without the wip
120 * array, worker threads remove two entries at a time from the beginning of 120 * array, worker threads remove two entries at a time from the beginning of
121 * the queue. These two entries are merged, and are added back to the tail 121 * the queue. These two entries are merged, and are added back to the tail
122 * of the queue, as follows: 122 * of the queue, as follows:
123 * 123 *
124 * Q: a b c d e # start 124 * Q: a b c d e # start
125 * Q: c d e ab # a, b removed, merged, added to end 125 * Q: c d e ab # a, b removed, merged, added to end
126 * Q: e ab cd # c, d removed, merged, added to end 126 * Q: e ab cd # c, d removed, merged, added to end
127 * Q: cd eab # e, ab removed, merged, added to end 127 * Q: cd eab # e, ab removed, merged, added to end
128 * Q: cdeab # cd, eab removed, merged, added to end 128 * Q: cdeab # cd, eab removed, merged, added to end
129 * 129 *
130 * When one entry remains on the queue, with no merges outstanding, Phase II 130 * When one entry remains on the queue, with no merges outstanding, Phase II
131 * finishes. We pre-determine the stopping point by pre-calculating the 131 * finishes. We pre-determine the stopping point by pre-calculating the
132 * number of nodes that will appear on the list. In the example above, the 132 * number of nodes that will appear on the list. In the example above, the
133 * number (wq_ninqueue) is 9. When ninqueue is 1, we conclude Phase II by 133 * number (wq_ninqueue) is 9. When ninqueue is 1, we conclude Phase II by
134 * signaling the main thread via wq_done_cv. 134 * signaling the main thread via wq_done_cv.
135 * 135 *
136 * Locking Semantics (Phase II) 136 * Locking Semantics (Phase II)
137 * 137 *
138 * The queue (wq_queue), ninqueue, and the master batch ID and last 138 * The queue (wq_queue), ninqueue, and the master batch ID and last
139 * completed batch counters are protected by wq_queue_lock. The done 139 * completed batch counters are protected by wq_queue_lock. The done
140 * queue and corresponding lock are unused in Phase II as is the wip array. 140 * queue and corresponding lock are unused in Phase II as is the wip array.
141 * 141 *
142 * Uniquification 142 * Uniquification
143 * 143 *
144 * We want the CTF data that goes into a given module to be as small as 144 * We want the CTF data that goes into a given module to be as small as
145 * possible. For example, we don't want it to contain any type data that may 145 * possible. For example, we don't want it to contain any type data that may
146 * be present in another common module. As such, after creating the master 146 * be present in another common module. As such, after creating the master
147 * tdata_t for a given module, we can, if requested by the user, uniquify it 147 * tdata_t for a given module, we can, if requested by the user, uniquify it
148 * against the tdata_t from another module (genunix in the case of the SunOS 148 * against the tdata_t from another module (genunix in the case of the SunOS
149 * kernel). We perform a merge between the tdata_t for this module and the 149 * kernel). We perform a merge between the tdata_t for this module and the
150 * tdata_t from genunix. Nodes found in this module that are not present in 150 * tdata_t from genunix. Nodes found in this module that are not present in
151 * genunix are added to a third tdata_t - the uniquified tdata_t. 151 * genunix are added to a third tdata_t - the uniquified tdata_t.
152 * 152 *
153 * Additive Merges 153 * Additive Merges
154 * 154 *
155 * In some cases, for example if we are issuing a new version of a common 155 * In some cases, for example if we are issuing a new version of a common
156 * module in a patch, we need to make sure that the CTF data already present 156 * module in a patch, we need to make sure that the CTF data already present
157 * in that module does not change. Changes to this data would void the CTF 157 * in that module does not change. Changes to this data would void the CTF
158 * data in any module that uniquified against the common module. To preserve 158 * data in any module that uniquified against the common module. To preserve
159 * the existing data, we can perform what is known as an additive merge. In 159 * the existing data, we can perform what is known as an additive merge. In
160 * this case, a final uniquification is performed against the CTF data in the 160 * this case, a final uniquification is performed against the CTF data in the
161 * previous version of the module. The result will be the placement of new 161 * previous version of the module. The result will be the placement of new
162 * and changed data after the existing data, thus preserving the existing type 162 * and changed data after the existing data, thus preserving the existing type
163 * ID space. 163 * ID space.
164 * 164 *
165 * Saving the result 165 * Saving the result
166 * 166 *
167 * When the merges are complete, the resulting tdata_t is placed into the 167 * When the merges are complete, the resulting tdata_t is placed into the
168 * output file, replacing the .SUNW_ctf section (if any) already in that file. 168 * output file, replacing the .SUNW_ctf section (if any) already in that file.
169 * 169 *
170 * The person who changes the merging thread code in this file without updating 170 * The person who changes the merging thread code in this file without updating
171 * this comment will not live to see the stock hit five. 171 * this comment will not live to see the stock hit five.
172 */ 172 */
173 173
174#if HAVE_NBTOOL_CONFIG_H 174#if HAVE_NBTOOL_CONFIG_H
175# include "nbtool_config.h" 175# include "nbtool_config.h"
176#endif 176#endif
177 177
178#include <stdio.h> 178#include <stdio.h>
179#include <stdlib.h> 179#include <stdlib.h>
180#include <unistd.h> 180#include <unistd.h>
181#include <pthread.h> 181#include <pthread.h>
182#include <assert.h> 182#include <assert.h>
183#if defined(sun) 183#if defined(sun)
184#include <synch.h> 184#include <synch.h>
185#endif 185#endif
186#include <signal.h> 186#include <signal.h>
187#include <libgen.h> 187#include <libgen.h>
188#include <string.h> 188#include <string.h>
189#include <errno.h> 189#include <errno.h>
190#if defined(sun) 190#if defined(sun)
191#include <alloca.h> 191#include <alloca.h>
192#endif 192#endif
193#include <sys/param.h> 193#include <sys/param.h>
194#include <sys/types.h> 194#include <sys/types.h>
195#include <sys/mman.h> 195#include <sys/mman.h>
196#if defined(sun) 196#if defined(sun)
197#include <sys/sysconf.h> 197#include <sys/sysconf.h>
198#endif 198#endif
199 199
200#include "ctf_headers.h" 200#include "ctf_headers.h"
201#include "ctftools.h" 201#include "ctftools.h"
202#include "ctfmerge.h" 202#include "ctfmerge.h"
203#include "traverse.h" 203#include "traverse.h"
204#include "memory.h" 204#include "memory.h"
205#include "fifo.h" 205#include "fifo.h"
206#include "barrier.h" 206#include "barrier.h"
207 207
208#pragma init(bigheap) 208#pragma init(bigheap)
209 209
210#define MERGE_PHASE1_BATCH_SIZE 8 210#define MERGE_PHASE1_BATCH_SIZE 8
 211#if 0
 212// XXX: bug?
211#define MERGE_PHASE1_MAX_SLOTS 5 213#define MERGE_PHASE1_MAX_SLOTS 5
 214#else
 215#define MERGE_PHASE1_MAX_SLOTS 1
 216#endif
212#define MERGE_INPUT_THROTTLE_LEN 10 217#define MERGE_INPUT_THROTTLE_LEN 10
213 218
214const char *progname; 219const char *progname;
215static char *outfile = NULL; 220static char *outfile = NULL;
216static char *tmpname = NULL; 221static char *tmpname = NULL;
217static int dynsym; 222static int dynsym;
218int debug_level = DEBUG_LEVEL; 223int debug_level = DEBUG_LEVEL;
219#if 0 224#if 0
220static size_t maxpgsize = 0x400000; 225static size_t maxpgsize = 0x400000;
221#endif 226#endif
222static int maxslots = MERGE_PHASE1_MAX_SLOTS; 227static int maxslots = MERGE_PHASE1_MAX_SLOTS;
223 228
224 229
225static void 230static void
226usage(void) 231usage(void)
227{ 232{
228 (void) fprintf(stderr, 233 (void) fprintf(stderr,
229 "Usage: %s [-fgstv] -l label | -L labelenv -o outfile file ...\n" 234 "Usage: %s [-fgstv] -l label | -L labelenv -o outfile file ...\n"
230 " %s [-fgstv] -l label | -L labelenv -o outfile -d uniqfile\n" 235 " %s [-fgstv] -l label | -L labelenv -o outfile -d uniqfile\n"
231 " %*s [-g] [-D uniqlabel] file ...\n" 236 " %*s [-g] [-D uniqlabel] file ...\n"
232 " %s [-fgstv] -l label | -L labelenv -o outfile -w withfile " 237 " %s [-fgstv] -l label | -L labelenv -o outfile -w withfile "
233 "file ...\n" 238 "file ...\n"
234 " %s [-g] -c srcfile destfile\n" 239 " %s [-g] -c srcfile destfile\n"
235 "\n" 240 "\n"
236 " Note: if -L labelenv is specified and labelenv is not set in\n" 241 " Note: if -L labelenv is specified and labelenv is not set in\n"
237 " the environment, a default value is used.\n", 242 " the environment, a default value is used.\n",
238 progname, progname, (int)strlen(progname), " ", 243 progname, progname, (int)strlen(progname), " ",
239 progname, progname); 244 progname, progname);
240} 245}
241 246
242#if defined(sun) 247#if defined(sun)
243static void 248static void
244bigheap(void) 249bigheap(void)
245{ 250{
246 size_t big, *size; 251 size_t big, *size;
247 int sizes; 252 int sizes;
248 struct memcntl_mha mha; 253 struct memcntl_mha mha;
249 254
250 /* 255 /*
251 * First, get the available pagesizes. 256 * First, get the available pagesizes.
252 */ 257 */
253 if ((sizes = getpagesizes(NULL, 0)) == -1) 258 if ((sizes = getpagesizes(NULL, 0)) == -1)
254 return; 259 return;
255 260
256 if (sizes == 1 || (size = alloca(sizeof (size_t) * sizes)) == NULL) 261 if (sizes == 1 || (size = alloca(sizeof (size_t) * sizes)) == NULL)
257 return; 262 return;
258 263
259 if (getpagesizes(size, sizes) == -1) 264 if (getpagesizes(size, sizes) == -1)
260 return; 265 return;
261 266
262 while (size[sizes - 1] > maxpgsize) 267 while (size[sizes - 1] > maxpgsize)
263 sizes--; 268 sizes--;
264 269
265 /* set big to the largest allowed page size */ 270 /* set big to the largest allowed page size */
266 big = size[sizes - 1]; 271 big = size[sizes - 1];
267 if (big & (big - 1)) { 272 if (big & (big - 1)) {
268 /* 273 /*
269 * The largest page size is not a power of two for some 274 * The largest page size is not a power of two for some
270 * inexplicable reason; return. 275 * inexplicable reason; return.
271 */ 276 */
272 return; 277 return;
273 } 278 }
274 279
275 /* 280 /*
276 * Now, align our break to the largest page size. 281 * Now, align our break to the largest page size.
277 */ 282 */
278 if (brk((void *)((((uintptr_t)sbrk(0) - 1) & ~(big - 1)) + big)) != 0) 283 if (brk((void *)((((uintptr_t)sbrk(0) - 1) & ~(big - 1)) + big)) != 0)
279 return; 284 return;
280 285
281 /* 286 /*
282 * set the preferred page size for the heap 287 * set the preferred page size for the heap
283 */ 288 */
284 mha.mha_cmd = MHA_MAPSIZE_BSSBRK; 289 mha.mha_cmd = MHA_MAPSIZE_BSSBRK;
285 mha.mha_flags = 0; 290 mha.mha_flags = 0;
286 mha.mha_pagesize = big; 291 mha.mha_pagesize = big;
287 292
288 (void) memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t)&mha, 0, 0); 293 (void) memcntl(NULL, 0, MC_HAT_ADVISE, (caddr_t)&mha, 0, 0);
289} 294}
290#endif 295#endif
291 296
292static void 297static void
293finalize_phase_one(workqueue_t *wq) 298finalize_phase_one(workqueue_t *wq)
294{ 299{
295 int startslot, i; 300 int startslot, i;
296 301
297 /* 302 /*
298 * wip slots are cleared out only when maxbatchsz td's have been merged 303 * wip slots are cleared out only when maxbatchsz td's have been merged
299 * into them. We're not guaranteed that the number of files we're 304 * into them. We're not guaranteed that the number of files we're
300 * merging is a multiple of maxbatchsz, so there will be some partial 305 * merging is a multiple of maxbatchsz, so there will be some partial
301 * groups in the wip array. Move them to the done queue in batch ID 306 * groups in the wip array. Move them to the done queue in batch ID
302 * order, starting with the slot containing the next batch that would 307 * order, starting with the slot containing the next batch that would
303 * have been placed on the done queue, followed by the others. 308 * have been placed on the done queue, followed by the others.
304 * One thread will be doing this while the others wait at the barrier 309 * One thread will be doing this while the others wait at the barrier
305 * back in worker_thread(), so we don't need to worry about pesky things 310 * back in worker_thread(), so we don't need to worry about pesky things
306 * like locks. 311 * like locks.
307 */ 312 */
308 313
309 for (startslot = -1, i = 0; i < wq->wq_nwipslots; i++) { 314 for (startslot = -1, i = 0; i < wq->wq_nwipslots; i++) {
310 if (wq->wq_wip[i].wip_batchid == wq->wq_lastdonebatch + 1) { 315 if (wq->wq_wip[i].wip_batchid == wq->wq_lastdonebatch + 1) {
311 startslot = i; 316 startslot = i;
312 break; 317 break;
313 } 318 }
314 } 319 }
315 320
316 assert(startslot != -1); 321 assert(startslot != -1);
317 322
318 for (i = startslot; i < startslot + wq->wq_nwipslots; i++) { 323 for (i = startslot; i < startslot + wq->wq_nwipslots; i++) {
319 int slotnum = i % wq->wq_nwipslots; 324 int slotnum = i % wq->wq_nwipslots;
320 wip_t *wipslot = &wq->wq_wip[slotnum]; 325 wip_t *wipslot = &wq->wq_wip[slotnum];
321 326
322 if (wipslot->wip_td != NULL) { 327 if (wipslot->wip_td != NULL) {
323 debug(2, "clearing slot %d (%d) (saving %d)\n", 328 debug(2, "clearing slot %d (%d) (saving %d)\n",
324 slotnum, i, wipslot->wip_nmerged); 329 slotnum, i, wipslot->wip_nmerged);
325 } else 330 } else
326 debug(2, "clearing slot %d (%d)\n", slotnum, i); 331 debug(2, "clearing slot %d (%d)\n", slotnum, i);
327 332
328 if (wipslot->wip_td != NULL) { 333 if (wipslot->wip_td != NULL) {
329 fifo_add(wq->wq_donequeue, wipslot->wip_td); 334 fifo_add(wq->wq_donequeue, wipslot->wip_td);
330 wq->wq_wip[slotnum].wip_td = NULL; 335 wq->wq_wip[slotnum].wip_td = NULL;
331 } 336 }
332 } 337 }
333 338
334 wq->wq_lastdonebatch = wq->wq_next_batchid++; 339 wq->wq_lastdonebatch = wq->wq_next_batchid++;
335 340
336 debug(2, "phase one done: donequeue has %d items\n", 341 debug(2, "phase one done: donequeue has %d items\n",
337 fifo_len(wq->wq_donequeue)); 342 fifo_len(wq->wq_donequeue));
338} 343}
339 344
340static void 345static void
341init_phase_two(workqueue_t *wq) 346init_phase_two(workqueue_t *wq)
342{ 347{
343 int num; 348 int num;
344 349
345 /* 350 /*
346 * We're going to continually merge the first two entries on the queue, 351 * We're going to continually merge the first two entries on the queue,
347 * placing the result on the end, until there's nothing left to merge. 352 * placing the result on the end, until there's nothing left to merge.
348 * At that point, everything will have been merged into one. The 353 * At that point, everything will have been merged into one. The
349 * initial value of ninqueue needs to be equal to the total number of 354 * initial value of ninqueue needs to be equal to the total number of
350 * entries that will show up on the queue, both at the start of the 355 * entries that will show up on the queue, both at the start of the
351 * phase and as generated by merges during the phase. 356 * phase and as generated by merges during the phase.
352 */ 357 */
353 wq->wq_ninqueue = num = fifo_len(wq->wq_donequeue); 358 wq->wq_ninqueue = num = fifo_len(wq->wq_donequeue);
354 while (num != 1) { 359 while (num != 1) {
355 wq->wq_ninqueue += num / 2; 360 wq->wq_ninqueue += num / 2;
356 num = num / 2 + num % 2; 361 num = num / 2 + num % 2;
357 } 362 }
358 363
359 /* 364 /*
360 * Move the done queue to the work queue. We won't be using the done 365 * Move the done queue to the work queue. We won't be using the done
361 * queue in phase 2. 366 * queue in phase 2.
362 */ 367 */
363 assert(fifo_len(wq->wq_queue) == 0); 368 assert(fifo_len(wq->wq_queue) == 0);
364 fifo_free(wq->wq_queue, NULL); 369 fifo_free(wq->wq_queue, NULL);
365 wq->wq_queue = wq->wq_donequeue; 370 wq->wq_queue = wq->wq_donequeue;
366} 371}
367 372
368static void 373static void
369wip_save_work(workqueue_t *wq, wip_t *slot, int slotnum) 374wip_save_work(workqueue_t *wq, wip_t *slot, int slotnum)
370{ 375{
371 pthread_mutex_lock(&wq->wq_donequeue_lock); 376 pthread_mutex_lock(&wq->wq_donequeue_lock);
372 377
373 while (wq->wq_lastdonebatch + 1 < slot->wip_batchid) 378 while (wq->wq_lastdonebatch + 1 < slot->wip_batchid)
374 pthread_cond_wait(&slot->wip_cv, &wq->wq_donequeue_lock); 379 pthread_cond_wait(&slot->wip_cv, &wq->wq_donequeue_lock);
375 assert(wq->wq_lastdonebatch + 1 == slot->wip_batchid); 380 assert(wq->wq_lastdonebatch + 1 == slot->wip_batchid);
376 381
377 fifo_add(wq->wq_donequeue, slot->wip_td); 382 fifo_add(wq->wq_donequeue, slot->wip_td);
378 wq->wq_lastdonebatch++; 383 wq->wq_lastdonebatch++;
379 pthread_cond_signal(&wq->wq_wip[(slotnum + 1) % 384 pthread_cond_signal(&wq->wq_wip[(slotnum + 1) %
380 wq->wq_nwipslots].wip_cv); 385 wq->wq_nwipslots].wip_cv);
381 386
382 /* reset the slot for next use */ 387 /* reset the slot for next use */
383 slot->wip_td = NULL; 388 slot->wip_td = NULL;
384 slot->wip_batchid = wq->wq_next_batchid++; 389 slot->wip_batchid = wq->wq_next_batchid++;
385 390
386 pthread_mutex_unlock(&wq->wq_donequeue_lock); 391 pthread_mutex_unlock(&wq->wq_donequeue_lock);
387} 392}
388 393
389static void 394static void
390wip_add_work(wip_t *slot, tdata_t *pow) 395wip_add_work(wip_t *slot, tdata_t *pow)
391{ 396{
392 if (slot->wip_td == NULL) { 397 if (slot->wip_td == NULL) {
393 slot->wip_td = pow; 398 slot->wip_td = pow;
394 slot->wip_nmerged = 1; 399 slot->wip_nmerged = 1;
395 } else { 400 } else {
396 debug(2, "0x%jx: merging %p into %p\n", 401 debug(2, "0x%jx: merging %p into %p\n",
397 (uintptr_t)pthread_self(), 402 (uintptr_t)pthread_self(),
398 (void *)pow, (void *)slot->wip_td); 403 (void *)pow, (void *)slot->wip_td);
399 404
400 merge_into_master(pow, slot->wip_td, NULL, 0); 405 merge_into_master(pow, slot->wip_td, NULL, 0);
401 tdata_free(pow); 406 tdata_free(pow);
402 407
403 slot->wip_nmerged++; 408 slot->wip_nmerged++;
404 } 409 }
405} 410}
406 411
407static void 412static void
408worker_runphase1(workqueue_t *wq) 413worker_runphase1(workqueue_t *wq)
409{ 414{
410 wip_t *wipslot; 415 wip_t *wipslot;
411 tdata_t *pow; 416 tdata_t *pow;
412 int wipslotnum, pownum; 417 int wipslotnum, pownum;
413 418
414 for (;;) { 419 for (;;) {
415 pthread_mutex_lock(&wq->wq_queue_lock); 420 pthread_mutex_lock(&wq->wq_queue_lock);
416 421
417 while (fifo_empty(wq->wq_queue)) { 422 while (fifo_empty(wq->wq_queue)) {
418 if (wq->wq_nomorefiles == 1) { 423 if (wq->wq_nomorefiles == 1) {
419 pthread_cond_broadcast(&wq->wq_work_avail); 424 pthread_cond_broadcast(&wq->wq_work_avail);
420 pthread_mutex_unlock(&wq->wq_queue_lock); 425 pthread_mutex_unlock(&wq->wq_queue_lock);
421 426
422 /* on to phase 2 ... */ 427 /* on to phase 2 ... */
423 return; 428 return;
424 } 429 }
425 430
426 pthread_cond_wait(&wq->wq_work_avail, 431 pthread_cond_wait(&wq->wq_work_avail,
427 &wq->wq_queue_lock); 432 &wq->wq_queue_lock);
428 } 433 }
429 434
430 /* there's work to be done! */ 435 /* there's work to be done! */
431 pow = fifo_remove(wq->wq_queue); 436 pow = fifo_remove(wq->wq_queue);
432 pownum = wq->wq_nextpownum++; 437 pownum = wq->wq_nextpownum++;
433 pthread_cond_broadcast(&wq->wq_work_removed); 438 pthread_cond_broadcast(&wq->wq_work_removed);
434 439
435 assert(pow != NULL); 440 assert(pow != NULL);
436 441
437 /* merge it into the right slot */ 442 /* merge it into the right slot */
438 wipslotnum = pownum % wq->wq_nwipslots; 443 wipslotnum = pownum % wq->wq_nwipslots;
439 wipslot = &wq->wq_wip[wipslotnum]; 444 wipslot = &wq->wq_wip[wipslotnum];
440 445
441 pthread_mutex_lock(&wipslot->wip_lock); 446 pthread_mutex_lock(&wipslot->wip_lock);
442 447
443 pthread_mutex_unlock(&wq->wq_queue_lock); 448 pthread_mutex_unlock(&wq->wq_queue_lock);
444 449
445 wip_add_work(wipslot, pow); 450 wip_add_work(wipslot, pow);
446 451
447 if (wipslot->wip_nmerged == wq->wq_maxbatchsz) 452 if (wipslot->wip_nmerged == wq->wq_maxbatchsz)
448 wip_save_work(wq, wipslot, wipslotnum); 453 wip_save_work(wq, wipslot, wipslotnum);
449 454
450 pthread_mutex_unlock(&wipslot->wip_lock); 455 pthread_mutex_unlock(&wipslot->wip_lock);
451 } 456 }
452} 457}
453 458
454static void 459static void
455worker_runphase2(workqueue_t *wq) 460worker_runphase2(workqueue_t *wq)
456{ 461{
457 tdata_t *pow1, *pow2; 462 tdata_t *pow1, *pow2;
458 int batchid; 463 int batchid;
459 464
460 for (;;) { 465 for (;;) {
461 pthread_mutex_lock(&wq->wq_queue_lock); 466 pthread_mutex_lock(&wq->wq_queue_lock);
462 467
463 if (wq->wq_ninqueue == 1) { 468 if (wq->wq_ninqueue == 1) {
464 pthread_cond_broadcast(&wq->wq_work_avail); 469 pthread_cond_broadcast(&wq->wq_work_avail);
465 pthread_mutex_unlock(&wq->wq_queue_lock); 470 pthread_mutex_unlock(&wq->wq_queue_lock);
466 471
467 debug(2, "0x%jx: entering p2 completion barrier\n", 472 debug(2, "0x%jx: entering p2 completion barrier\n",
468 (uintptr_t)pthread_self()); 473 (uintptr_t)pthread_self());
469 if (barrier_wait(&wq->wq_bar1)) { 474 if (barrier_wait(&wq->wq_bar1)) {
470 pthread_mutex_lock(&wq->wq_queue_lock); 475 pthread_mutex_lock(&wq->wq_queue_lock);
471 wq->wq_alldone = 1; 476 wq->wq_alldone = 1;
472 pthread_cond_signal(&wq->wq_alldone_cv); 477 pthread_cond_signal(&wq->wq_alldone_cv);
473 pthread_mutex_unlock(&wq->wq_queue_lock); 478 pthread_mutex_unlock(&wq->wq_queue_lock);
474 } 479 }
475 480
476 return; 481 return;
477 } 482 }
478 483
479 if (fifo_len(wq->wq_queue) < 2) { 484 if (fifo_len(wq->wq_queue) < 2) {
480 pthread_cond_wait(&wq->wq_work_avail, 485 pthread_cond_wait(&wq->wq_work_avail,
481 &wq->wq_queue_lock); 486 &wq->wq_queue_lock);
482 pthread_mutex_unlock(&wq->wq_queue_lock); 487 pthread_mutex_unlock(&wq->wq_queue_lock);
483 continue; 488 continue;
484 } 489 }
485 490
486 /* there's work to be done! */ 491 /* there's work to be done! */
487 pow1 = fifo_remove(wq->wq_queue); 492 pow1 = fifo_remove(wq->wq_queue);
488 pow2 = fifo_remove(wq->wq_queue); 493 pow2 = fifo_remove(wq->wq_queue);
489 wq->wq_ninqueue -= 2; 494 wq->wq_ninqueue -= 2;
490 495
491 batchid = wq->wq_next_batchid++; 496 batchid = wq->wq_next_batchid++;
492 497
493 pthread_mutex_unlock(&wq->wq_queue_lock); 498 pthread_mutex_unlock(&wq->wq_queue_lock);
494 499
495 debug(2, "0x%jx: merging %p into %p\n", 500 debug(2, "0x%jx: merging %p into %p\n",
496 (uintptr_t)pthread_self(), 501 (uintptr_t)pthread_self(),
497 (void *)pow1, (void *)pow2); 502 (void *)pow1, (void *)pow2);
498 merge_into_master(pow1, pow2, NULL, 0); 503 merge_into_master(pow1, pow2, NULL, 0);
499 tdata_free(pow1); 504 tdata_free(pow1);
500 505
501 /* 506 /*
502 * merging is complete. place at the tail of the queue in 507 * merging is complete. place at the tail of the queue in
503 * proper order. 508 * proper order.
504 */ 509 */
505 pthread_mutex_lock(&wq->wq_queue_lock); 510 pthread_mutex_lock(&wq->wq_queue_lock);
506 while (wq->wq_lastdonebatch + 1 != batchid) { 511 while (wq->wq_lastdonebatch + 1 != batchid) {
507 pthread_cond_wait(&wq->wq_done_cv, 512 pthread_cond_wait(&wq->wq_done_cv,
508 &wq->wq_queue_lock); 513 &wq->wq_queue_lock);
509 } 514 }
510 515
511 wq->wq_lastdonebatch = batchid; 516 wq->wq_lastdonebatch = batchid;
512 517
513 fifo_add(wq->wq_queue, pow2); 518 fifo_add(wq->wq_queue, pow2);
514 debug(2, "0x%jx: added %p to queue, len now %d, ninqueue %d\n", 519 debug(2, "0x%jx: added %p to queue, len now %d, ninqueue %d\n",
515 (uintptr_t)pthread_self(), (void *)pow2, 520 (uintptr_t)pthread_self(), (void *)pow2,
516 fifo_len(wq->wq_queue), wq->wq_ninqueue); 521 fifo_len(wq->wq_queue), wq->wq_ninqueue);
517 pthread_cond_broadcast(&wq->wq_done_cv); 522 pthread_cond_broadcast(&wq->wq_done_cv);
518 pthread_cond_signal(&wq->wq_work_avail); 523 pthread_cond_signal(&wq->wq_work_avail);
519 pthread_mutex_unlock(&wq->wq_queue_lock); 524 pthread_mutex_unlock(&wq->wq_queue_lock);
520 } 525 }
521} 526}
522 527
523/* 528/*
524 * Main loop for worker threads. 529 * Main loop for worker threads.
525 */ 530 */
526static void 531static void
527worker_thread(workqueue_t *wq) 532worker_thread(workqueue_t *wq)
528{ 533{
529 worker_runphase1(wq); 534 worker_runphase1(wq);
530 535
531 debug(2, "0x%jx: entering first barrier\n", (uintptr_t)pthread_self()); 536 debug(2, "0x%jx: entering first barrier\n", (uintptr_t)pthread_self());
532 537
533 if (barrier_wait(&wq->wq_bar1)) { 538 if (barrier_wait(&wq->wq_bar1)) {
534 539
535 debug(2, "0x%jx: doing work in first barrier\n", 540 debug(2, "0x%jx: doing work in first barrier\n",
536 (uintptr_t)pthread_self()); 541 (uintptr_t)pthread_self());
537 542
538 finalize_phase_one(wq); 543 finalize_phase_one(wq);
539 544
540 init_phase_two(wq); 545 init_phase_two(wq);
541 546
542 debug(2, "0x%jx: ninqueue is %d, %d on queue\n", 547 debug(2, "0x%jx: ninqueue is %d, %d on queue\n",
543 (uintptr_t)pthread_self(), 548 (uintptr_t)pthread_self(),
544 wq->wq_ninqueue, fifo_len(wq->wq_queue)); 549 wq->wq_ninqueue, fifo_len(wq->wq_queue));
545 } 550 }
546 551
547 debug(2, "0x%jx: entering second barrier\n", (uintptr_t)pthread_self()); 552 debug(2, "0x%jx: entering second barrier\n", (uintptr_t)pthread_self());
548 553
549 (void) barrier_wait(&wq->wq_bar2); 554 (void) barrier_wait(&wq->wq_bar2);
550 555
551 debug(2, "0x%jx: phase 1 complete\n", (uintptr_t)pthread_self()); 556 debug(2, "0x%jx: phase 1 complete\n", (uintptr_t)pthread_self());
552 557
553 worker_runphase2(wq); 558 worker_runphase2(wq);
554} 559}
555 560
556/* 561/*
557 * Pass a tdata_t tree, built from an input file, off to the work queue for 562 * Pass a tdata_t tree, built from an input file, off to the work queue for
558 * consumption by worker threads. 563 * consumption by worker threads.
559 */ 564 */
560static int 565static int
561merge_ctf_cb(tdata_t *td, char *name, void *arg) 566merge_ctf_cb(tdata_t *td, char *name, void *arg)
562{ 567{
563 workqueue_t *wq = arg; 568 workqueue_t *wq = arg;
564 569
565 debug(3, "Adding tdata %p for processing\n", (void *)td); 570 debug(3, "Adding tdata %p for processing\n", (void *)td);
566 571
567 pthread_mutex_lock(&wq->wq_queue_lock); 572 pthread_mutex_lock(&wq->wq_queue_lock);
568 while (fifo_len(wq->wq_queue) > wq->wq_ithrottle) { 573 while (fifo_len(wq->wq_queue) > wq->wq_ithrottle) {
569 debug(2, "Throttling input (len = %d, throttle = %d)\n", 574 debug(2, "Throttling input (len = %d, throttle = %d)\n",
570 fifo_len(wq->wq_queue), wq->wq_ithrottle); 575 fifo_len(wq->wq_queue), wq->wq_ithrottle);
571 pthread_cond_wait(&wq->wq_work_removed, &wq->wq_queue_lock); 576 pthread_cond_wait(&wq->wq_work_removed, &wq->wq_queue_lock);
572 } 577 }
573 578
574 fifo_add(wq->wq_queue, td); 579 fifo_add(wq->wq_queue, td);
575 debug(1, "Thread 0x%jx announcing %s\n", (uintptr_t)pthread_self(), 580 debug(1, "Thread 0x%jx announcing %s\n", (uintptr_t)pthread_self(),
576 name); 581 name);
577 pthread_cond_broadcast(&wq->wq_work_avail); 582 pthread_cond_broadcast(&wq->wq_work_avail);
578 pthread_mutex_unlock(&wq->wq_queue_lock); 583 pthread_mutex_unlock(&wq->wq_queue_lock);
579 584
580 return (1); 585 return (1);
581} 586}
582 587
583/* 588/*
584 * This program is intended to be invoked from a Makefile, as part of the build. 589 * This program is intended to be invoked from a Makefile, as part of the build.
585 * As such, in the event of a failure or user-initiated interrupt (^C), we need 590 * As such, in the event of a failure or user-initiated interrupt (^C), we need
586 * to ensure that a subsequent re-make will cause ctfmerge to be executed again. 591 * to ensure that a subsequent re-make will cause ctfmerge to be executed again.
587 * Unfortunately, ctfmerge will usually be invoked directly after (and as part 592 * Unfortunately, ctfmerge will usually be invoked directly after (and as part
588 * of the same Makefile rule as) a link, and will operate on the linked file 593 * of the same Makefile rule as) a link, and will operate on the linked file
589 * in place. If we merely exit upon receipt of a SIGINT, a subsequent make 594 * in place. If we merely exit upon receipt of a SIGINT, a subsequent make
590 * will notice that the *linked* file is newer than the object files, and thus 595 * will notice that the *linked* file is newer than the object files, and thus
591 * will not reinvoke ctfmerge. The only way to ensure that a subsequent make 596 * will not reinvoke ctfmerge. The only way to ensure that a subsequent make
592 * reinvokes ctfmerge, is to remove the file to which we are adding CTF 597 * reinvokes ctfmerge, is to remove the file to which we are adding CTF
593 * data (confusingly named the output file). This means that the link will need 598 * data (confusingly named the output file). This means that the link will need
594 * to happen again, but links are generally fast, and we can't allow the merge 599 * to happen again, but links are generally fast, and we can't allow the merge
595 * to be skipped. 600 * to be skipped.
596 * 601 *
597 * Another possibility would be to block SIGINT entirely - to always run to 602 * Another possibility would be to block SIGINT entirely - to always run to
598 * completion. The run time of ctfmerge can, however, be measured in minutes 603 * completion. The run time of ctfmerge can, however, be measured in minutes
599 * in some cases, so this is not a valid option. 604 * in some cases, so this is not a valid option.
600 */ 605 */
601static void 606static void
602handle_sig(int sig) 607handle_sig(int sig)
603{ 608{
604 terminate("Caught signal %d - exiting\n", sig); 609 terminate("Caught signal %d - exiting\n", sig);
605} 610}
606 611
607static void 612static void
608terminate_cleanup(void) 613terminate_cleanup(void)
609{ 614{
610 int dounlink = getenv("CTFMERGE_TERMINATE_NO_UNLINK") ? 0 : 1; 615 int dounlink = getenv("CTFMERGE_TERMINATE_NO_UNLINK") ? 0 : 1;
611 616
612 if (tmpname != NULL && dounlink) 617 if (tmpname != NULL && dounlink)
613 unlink(tmpname); 618 unlink(tmpname);
614 619
615 if (outfile == NULL) 620 if (outfile == NULL)
616 return; 621 return;
617 622
618#if !defined(__FreeBSD__) 623#if !defined(__FreeBSD__)
619 if (dounlink) { 624 if (dounlink) {
620 fprintf(stderr, "Removing %s\n", outfile); 625 fprintf(stderr, "Removing %s\n", outfile);
621 unlink(outfile); 626 unlink(outfile);
622 } 627 }
623#endif 628#endif
624} 629}
625 630
626static void 631static void
627copy_ctf_data(char *srcfile, char *destfile, int keep_stabs) 632copy_ctf_data(char *srcfile, char *destfile, int keep_stabs)
628{ 633{
629 tdata_t *srctd; 634 tdata_t *srctd;
630 635
631 if (read_ctf(&srcfile, 1, NULL, read_ctf_save_cb, &srctd, 1) == 0) 636 if (read_ctf(&srcfile, 1, NULL, read_ctf_save_cb, &srctd, 1) == 0)
632 terminate("No CTF data found in source file %s\n", srcfile); 637 terminate("No CTF data found in source file %s\n", srcfile);
633 638
634 tmpname = mktmpname(destfile, ".ctf"); 639 tmpname = mktmpname(destfile, ".ctf");
635 write_ctf(srctd, destfile, tmpname, CTF_COMPRESS | CTF_SWAP_BYTES | keep_stabs); 640 write_ctf(srctd, destfile, tmpname, CTF_COMPRESS | CTF_SWAP_BYTES | keep_stabs);
636 if (rename(tmpname, destfile) != 0) { 641 if (rename(tmpname, destfile) != 0) {
637 terminate("Couldn't rename temp file %s to %s", tmpname, 642 terminate("Couldn't rename temp file %s to %s", tmpname,
638 destfile); 643 destfile);
639 } 644 }
640 free(tmpname); 645 free(tmpname);
641 tdata_free(srctd); 646 tdata_free(srctd);
642} 647}
643 648
644static void 649static void
645wq_init(workqueue_t *wq, int nfiles) 650wq_init(workqueue_t *wq, int nfiles)
646{ 651{
647 int throttle, nslots, i; 652 int throttle, nslots, i;
648 653
649 if (getenv("CTFMERGE_MAX_SLOTS")) 654 if (getenv("CTFMERGE_MAX_SLOTS"))
650 nslots = atoi(getenv("CTFMERGE_MAX_SLOTS")); 655 nslots = atoi(getenv("CTFMERGE_MAX_SLOTS"));
651 else 656 else
652 nslots = maxslots; 657 nslots = maxslots;
653 658
654 if (getenv("CTFMERGE_PHASE1_BATCH_SIZE")) 659 if (getenv("CTFMERGE_PHASE1_BATCH_SIZE"))
655 wq->wq_maxbatchsz = atoi(getenv("CTFMERGE_PHASE1_BATCH_SIZE")); 660 wq->wq_maxbatchsz = atoi(getenv("CTFMERGE_PHASE1_BATCH_SIZE"));
656 else 661 else
657 wq->wq_maxbatchsz = MERGE_PHASE1_BATCH_SIZE; 662 wq->wq_maxbatchsz = MERGE_PHASE1_BATCH_SIZE;
658 663
659 nslots = MIN(nslots, (nfiles + wq->wq_maxbatchsz - 1) / 664 nslots = MIN(nslots, (nfiles + wq->wq_maxbatchsz - 1) /
660 wq->wq_maxbatchsz); 665 wq->wq_maxbatchsz);
661 666
662 wq->wq_wip = xcalloc(sizeof (wip_t) * nslots); 667 wq->wq_wip = xcalloc(sizeof (wip_t) * nslots);
663 wq->wq_nwipslots = nslots; 668 wq->wq_nwipslots = nslots;
664#ifdef _SC_NPROCESSORS_ONLN 669#ifdef _SC_NPROCESSORS_ONLN
665 wq->wq_nthreads = MIN(sysconf(_SC_NPROCESSORS_ONLN) * 3 / 2, nslots); 670 wq->wq_nthreads = MIN(sysconf(_SC_NPROCESSORS_ONLN) * 3 / 2, nslots);
666#else 671#else
667 wq->wq_nthreads = 2; 672 wq->wq_nthreads = 2;
668#endif 673#endif
669 wq->wq_thread = xmalloc(sizeof (pthread_t) * wq->wq_nthreads); 674 wq->wq_thread = xmalloc(sizeof (pthread_t) * wq->wq_nthreads);
670 675
671 if (getenv("CTFMERGE_INPUT_THROTTLE")) 676 if (getenv("CTFMERGE_INPUT_THROTTLE"))
672 throttle = atoi(getenv("CTFMERGE_INPUT_THROTTLE")); 677 throttle = atoi(getenv("CTFMERGE_INPUT_THROTTLE"));
673 else 678 else
674 throttle = MERGE_INPUT_THROTTLE_LEN; 679 throttle = MERGE_INPUT_THROTTLE_LEN;
675 wq->wq_ithrottle = throttle * wq->wq_nthreads; 680 wq->wq_ithrottle = throttle * wq->wq_nthreads;
676 681
677 debug(1, "Using %d slots, %d threads\n", wq->wq_nwipslots, 682 debug(1, "Using %d slots, %d threads\n", wq->wq_nwipslots,
678 wq->wq_nthreads); 683 wq->wq_nthreads);
679 684
680 wq->wq_next_batchid = 0; 685 wq->wq_next_batchid = 0;
681 686
682 for (i = 0; i < nslots; i++) { 687 for (i = 0; i < nslots; i++) {
683 pthread_mutex_init(&wq->wq_wip[i].wip_lock, NULL); 688 pthread_mutex_init(&wq->wq_wip[i].wip_lock, NULL);
684 wq->wq_wip[i].wip_batchid = wq->wq_next_batchid++; 689 wq->wq_wip[i].wip_batchid = wq->wq_next_batchid++;
685 } 690 }
686 691
687 pthread_mutex_init(&wq->wq_queue_lock, NULL); 692 pthread_mutex_init(&wq->wq_queue_lock, NULL);
688 wq->wq_queue = fifo_new(); 693 wq->wq_queue = fifo_new();
689 pthread_cond_init(&wq->wq_work_avail, NULL); 694 pthread_cond_init(&wq->wq_work_avail, NULL);
690 pthread_cond_init(&wq->wq_work_removed, NULL); 695 pthread_cond_init(&wq->wq_work_removed, NULL);
691 wq->wq_ninqueue = nfiles; 696 wq->wq_ninqueue = nfiles;
692 wq->wq_nextpownum = 0; 697 wq->wq_nextpownum = 0;
693 698
694 pthread_mutex_init(&wq->wq_donequeue_lock, NULL); 699 pthread_mutex_init(&wq->wq_donequeue_lock, NULL);
695 wq->wq_donequeue = fifo_new(); 700 wq->wq_donequeue = fifo_new();
696 wq->wq_lastdonebatch = -1; 701 wq->wq_lastdonebatch = -1;
697 702
698 pthread_cond_init(&wq->wq_done_cv, NULL); 703 pthread_cond_init(&wq->wq_done_cv, NULL);
699 704
700 pthread_cond_init(&wq->wq_alldone_cv, NULL); 705 pthread_cond_init(&wq->wq_alldone_cv, NULL);
701 wq->wq_alldone = 0; 706 wq->wq_alldone = 0;
702 707
703 barrier_init(&wq->wq_bar1, wq->wq_nthreads); 708 barrier_init(&wq->wq_bar1, wq->wq_nthreads);
704 barrier_init(&wq->wq_bar2, wq->wq_nthreads); 709 barrier_init(&wq->wq_bar2, wq->wq_nthreads);
705 710
706 wq->wq_nomorefiles = 0; 711 wq->wq_nomorefiles = 0;
707} 712}
708 713
709static void 714static void
710start_threads(workqueue_t *wq) 715start_threads(workqueue_t *wq)
711{ 716{
712 sigset_t sets; 717 sigset_t sets;
713 int i; 718 int i;
714 719
715 sigemptyset(&sets); 720 sigemptyset(&sets);
716 sigaddset(&sets, SIGINT); 721 sigaddset(&sets, SIGINT);
717 sigaddset(&sets, SIGQUIT); 722 sigaddset(&sets, SIGQUIT);
718 sigaddset(&sets, SIGTERM); 723 sigaddset(&sets, SIGTERM);
719 pthread_sigmask(SIG_BLOCK, &sets, NULL); 724 pthread_sigmask(SIG_BLOCK, &sets, NULL);
720 725
721 for (i = 0; i < wq->wq_nthreads; i++) { 726 for (i = 0; i < wq->wq_nthreads; i++) {
722 pthread_create(&wq->wq_thread[i], NULL, 727 pthread_create(&wq->wq_thread[i], NULL,
723 (void *(*)(void *))worker_thread, wq); 728 (void *(*)(void *))worker_thread, wq);
724 } 729 }
725 730
726#if defined(sun) 731#if defined(sun)
727 sigset(SIGINT, handle_sig); 732 sigset(SIGINT, handle_sig);
728 sigset(SIGQUIT, handle_sig); 733 sigset(SIGQUIT, handle_sig);
729 sigset(SIGTERM, handle_sig); 734 sigset(SIGTERM, handle_sig);
730#else 735#else
731 signal(SIGINT, handle_sig); 736 signal(SIGINT, handle_sig);
732 signal(SIGQUIT, handle_sig); 737 signal(SIGQUIT, handle_sig);
733 signal(SIGTERM, handle_sig); 738 signal(SIGTERM, handle_sig);
734#endif 739#endif
735 pthread_sigmask(SIG_UNBLOCK, &sets, NULL); 740 pthread_sigmask(SIG_UNBLOCK, &sets, NULL);
736} 741}
737 742
738static void 743static void
739join_threads(workqueue_t *wq) 744join_threads(workqueue_t *wq)
740{ 745{
741 int i; 746 int i;
742 747
743 for (i = 0; i < wq->wq_nthreads; i++) { 748 for (i = 0; i < wq->wq_nthreads; i++) {
744 pthread_join(wq->wq_thread[i], NULL); 749 pthread_join(wq->wq_thread[i], NULL);
745 } 750 }
746} 751}
747 752
748static int 753static int
749strcompare(const void *p1, const void *p2) 754strcompare(const void *p1, const void *p2)
750{ 755{
751 const char *s1 = *((const char * const *)p1); 756 const char *s1 = *((const char * const *)p1);
752 const char *s2 = *((const char * const *)p2); 757 const char *s2 = *((const char * const *)p2);
753 758
754 return (strcmp(s1, s2)); 759 return (strcmp(s1, s2));
755} 760}
756 761
757/* 762/*
758 * Core work queue structure; passed to worker threads on thread creation 763 * Core work queue structure; passed to worker threads on thread creation
759 * as the main point of coordination. Allocate as a static structure; we 764 * as the main point of coordination. Allocate as a static structure; we
760 * could have put this into a local variable in main, but passing a pointer 765 * could have put this into a local variable in main, but passing a pointer
761 * into your stack to another thread is fragile at best and leads to some 766 * into your stack to another thread is fragile at best and leads to some
762 * hard-to-debug failure modes. 767 * hard-to-debug failure modes.
763 */ 768 */
764static workqueue_t wq; 769static workqueue_t wq;
765 770
766int 771int
767main(int argc, char **argv) 772main(int argc, char **argv)
768{ 773{
769 tdata_t *mstrtd, *savetd; 774 tdata_t *mstrtd, *savetd;
770 char *uniqfile = NULL, *uniqlabel = NULL; 775 char *uniqfile = NULL, *uniqlabel = NULL;
771 char *withfile = NULL; 776 char *withfile = NULL;
772 char *label = NULL; 777 char *label = NULL;
773 char **ifiles, **tifiles; 778 char **ifiles, **tifiles;
774 int verbose = 0, docopy = 0; 779 int verbose = 0, docopy = 0;
775 int write_fuzzy_match = 0; 780 int write_fuzzy_match = 0;
776 int keep_stabs = 0; 781 int keep_stabs = 0;
777 int require_ctf = 0; 782 int require_ctf = 0;
778 int nifiles, nielems; 783 int nifiles, nielems;
779 int c, i, idx, tidx, err; 784 int c, i, idx, tidx, err;
780 785
781 progname = basename(argv[0]); 786 progname = basename(argv[0]);
782 787
783 if (getenv("CTFMERGE_DEBUG_LEVEL")) 788 if (getenv("CTFMERGE_DEBUG_LEVEL"))
784 debug_level = atoi(getenv("CTFMERGE_DEBUG_LEVEL")); 789 debug_level = atoi(getenv("CTFMERGE_DEBUG_LEVEL"));
785 790
786 err = 0; 791 err = 0;
787 while ((c = getopt(argc, argv, ":cd:D:fgl:L:o:tvw:sS:")) != EOF) { 792 while ((c = getopt(argc, argv, ":cd:D:fgl:L:o:tvw:sS:")) != EOF) {
788 switch (c) { 793 switch (c) {
789 case 'c': 794 case 'c':
790 docopy = 1; 795 docopy = 1;
791 break; 796 break;
792 case 'd': 797 case 'd':
793 /* Uniquify against `uniqfile' */ 798 /* Uniquify against `uniqfile' */
794 uniqfile = optarg; 799 uniqfile = optarg;
795 break; 800 break;
796 case 'D': 801 case 'D':
797 /* Uniquify against label `uniqlabel' in `uniqfile' */ 802 /* Uniquify against label `uniqlabel' in `uniqfile' */
798 uniqlabel = optarg; 803 uniqlabel = optarg;
799 break; 804 break;
800 case 'f': 805 case 'f':
801 write_fuzzy_match = CTF_FUZZY_MATCH; 806 write_fuzzy_match = CTF_FUZZY_MATCH;
802 break; 807 break;
803 case 'g': 808 case 'g':
804 keep_stabs = CTF_KEEP_STABS; 809 keep_stabs = CTF_KEEP_STABS;
805 break; 810 break;
806 case 'l': 811 case 'l':
807 /* Label merged types with `label' */ 812 /* Label merged types with `label' */
808 label = optarg; 813 label = optarg;
809 break; 814 break;
810 case 'L': 815 case 'L':
811 /* Label merged types with getenv(`label`) */ 816 /* Label merged types with getenv(`label`) */
812 if ((label = getenv(optarg)) == NULL) 817 if ((label = getenv(optarg)) == NULL)
813 label = __UNCONST(CTF_DEFAULT_LABEL); 818 label = __UNCONST(CTF_DEFAULT_LABEL);
814 break; 819 break;
815 case 'o': 820 case 'o':
816 /* Place merged types in CTF section in `outfile' */ 821 /* Place merged types in CTF section in `outfile' */
817 outfile = optarg; 822 outfile = optarg;
818 break; 823 break;
819 case 't': 824 case 't':
820 /* Insist *all* object files built from C have CTF */ 825 /* Insist *all* object files built from C have CTF */
821 require_ctf = 1; 826 require_ctf = 1;
822 break; 827 break;
823 case 'v': 828 case 'v':
824 /* More debugging information */ 829 /* More debugging information */
825 verbose = 1; 830 verbose = 1;
826 break; 831 break;
827 case 'w': 832 case 'w':
828 /* Additive merge with data from `withfile' */ 833 /* Additive merge with data from `withfile' */
829 withfile = optarg; 834 withfile = optarg;
830 break; 835 break;
831 case 's': 836 case 's':
832 /* use the dynsym rather than the symtab */ 837 /* use the dynsym rather than the symtab */
833 dynsym = CTF_USE_DYNSYM; 838 dynsym = CTF_USE_DYNSYM;
834 break; 839 break;
835 case 'S': 840 case 'S':
836 maxslots = atoi(optarg); 841 maxslots = atoi(optarg);
837 break; 842 break;
838 default: 843 default:
839 usage(); 844 usage();
840 exit(2); 845 exit(2);
841 } 846 }
842 } 847 }
843 848
844 /* Validate arguments */ 849 /* Validate arguments */
845 if (docopy) { 850 if (docopy) {
846 if (uniqfile != NULL || uniqlabel != NULL || label != NULL || 851 if (uniqfile != NULL || uniqlabel != NULL || label != NULL ||
847 outfile != NULL || withfile != NULL || dynsym != 0) 852 outfile != NULL || withfile != NULL || dynsym != 0)
848 err++; 853 err++;
849 854
850 if (argc - optind != 2) 855 if (argc - optind != 2)
851 err++; 856 err++;
852 } else { 857 } else {
853 if (uniqfile != NULL && withfile != NULL) 858 if (uniqfile != NULL && withfile != NULL)
854 err++; 859 err++;
855 860
856 if (uniqlabel != NULL && uniqfile == NULL) 861 if (uniqlabel != NULL && uniqfile == NULL)
857 err++; 862 err++;
858 863
859 if (outfile == NULL || label == NULL) 864 if (outfile == NULL || label == NULL)
860 err++; 865 err++;
861 866
862 if (argc - optind == 0) 867 if (argc - optind == 0)
863 err++; 868 err++;
864 } 869 }
865 870
866 if (err) { 871 if (err) {
867 usage(); 872 usage();
868 exit(2); 873 exit(2);
869 } 874 }
870 875
871 if (getenv("STRIPSTABS_KEEP_STABS") != NULL) 876 if (getenv("STRIPSTABS_KEEP_STABS") != NULL)
872 keep_stabs = CTF_KEEP_STABS; 877 keep_stabs = CTF_KEEP_STABS;
873 878
874 if (uniqfile && access(uniqfile, R_OK) != 0) { 879 if (uniqfile && access(uniqfile, R_OK) != 0) {
875 warning("Uniquification file %s couldn't be opened and " 880 warning("Uniquification file %s couldn't be opened and "
876 "will be ignored.\n", uniqfile); 881 "will be ignored.\n", uniqfile);
877 uniqfile = NULL; 882 uniqfile = NULL;
878 } 883 }
879 if (withfile && access(withfile, R_OK) != 0) { 884 if (withfile && access(withfile, R_OK) != 0) {
880 warning("With file %s couldn't be opened and will be " 885 warning("With file %s couldn't be opened and will be "
881 "ignored.\n", withfile); 886 "ignored.\n", withfile);
882 withfile = NULL; 887 withfile = NULL;
883 } 888 }
884 if (outfile && access(outfile, R_OK|W_OK) != 0) 889 if (outfile && access(outfile, R_OK|W_OK) != 0)
885 terminate("Cannot open output file %s for r/w", outfile); 890 terminate("Cannot open output file %s for r/w", outfile);
886 891
887 /* 892 /*
888 * This is ugly, but we don't want to have to have a separate tool 893 * This is ugly, but we don't want to have to have a separate tool
889 * (yet) just for copying an ELF section with our specific requirements, 894 * (yet) just for copying an ELF section with our specific requirements,
890 * so we shoe-horn a copier into ctfmerge. 895 * so we shoe-horn a copier into ctfmerge.
891 */ 896 */
892 if (docopy) { 897 if (docopy) {
893 copy_ctf_data(argv[optind], argv[optind + 1], keep_stabs); 898 copy_ctf_data(argv[optind], argv[optind + 1], keep_stabs);
894 899
895 exit(0); 900 exit(0);
896 } 901 }
897 902
898 set_terminate_cleanup(terminate_cleanup); 903 set_terminate_cleanup(terminate_cleanup);
899 904
900 /* Sort the input files and strip out duplicates */ 905 /* Sort the input files and strip out duplicates */
901 nifiles = argc - optind; 906 nifiles = argc - optind;
902 ifiles = xmalloc(sizeof (char *) * nifiles); 907 ifiles = xmalloc(sizeof (char *) * nifiles);
903 tifiles = xmalloc(sizeof (char *) * nifiles); 908 tifiles = xmalloc(sizeof (char *) * nifiles);
904 909
905 for (i = 0; i < nifiles; i++) 910 for (i = 0; i < nifiles; i++)
906 tifiles[i] = argv[optind + i]; 911 tifiles[i] = argv[optind + i];
907 qsort(tifiles, nifiles, sizeof (char *), strcompare); 912 qsort(tifiles, nifiles, sizeof (char *), strcompare);
908 913
909 ifiles[0] = tifiles[0]; 914 ifiles[0] = tifiles[0];
910 for (idx = 0, tidx = 1; tidx < nifiles; tidx++) { 915 for (idx = 0, tidx = 1; tidx < nifiles; tidx++) {
911 if (strcmp(ifiles[idx], tifiles[tidx]) != 0) 916 if (strcmp(ifiles[idx], tifiles[tidx]) != 0)
912 ifiles[++idx] = tifiles[tidx]; 917 ifiles[++idx] = tifiles[tidx];
913 } 918 }
914 nifiles = idx + 1; 919 nifiles = idx + 1;
915 920
916 /* Make sure they all exist */ 921 /* Make sure they all exist */
917 if ((nielems = count_files(ifiles, nifiles)) < 0) 922 if ((nielems = count_files(ifiles, nifiles)) < 0)
918 terminate("Some input files were inaccessible\n"); 923 terminate("Some input files were inaccessible\n");
919 924
920 /* Prepare for the merge */ 925 /* Prepare for the merge */
921 wq_init(&wq, nielems); 926 wq_init(&wq, nielems);
922 927
923 start_threads(&wq); 928 start_threads(&wq);
924 929
925 /* 930 /*
926 * Start the merge 931 * Start the merge
927 * 932 *
928 * We're reading everything from each of the object files, so we 933 * We're reading everything from each of the object files, so we
929 * don't need to specify labels. 934 * don't need to specify labels.
930 */ 935 */
931 if (read_ctf(ifiles, nifiles, NULL, merge_ctf_cb, 936 if (read_ctf(ifiles, nifiles, NULL, merge_ctf_cb,
932 &wq, require_ctf) == 0) { 937 &wq, require_ctf) == 0) {
933 /* 938 /*
934 * If we're verifying that C files have CTF, it's safe to 939 * If we're verifying that C files have CTF, it's safe to
935 * assume that in this case, we're building only from assembly 940 * assume that in this case, we're building only from assembly
936 * inputs. 941 * inputs.
937 */ 942 */
938 if (require_ctf) 943 if (require_ctf)
939 exit(0); 944 exit(0);
940 terminate("No ctf sections found to merge\n"); 945 terminate("No ctf sections found to merge\n");
941 } 946 }
942 947
943 pthread_mutex_lock(&wq.wq_queue_lock); 948 pthread_mutex_lock(&wq.wq_queue_lock);
944 wq.wq_nomorefiles = 1; 949 wq.wq_nomorefiles = 1;
945 pthread_cond_broadcast(&wq.wq_work_avail); 950 pthread_cond_broadcast(&wq.wq_work_avail);
946 pthread_mutex_unlock(&wq.wq_queue_lock); 951 pthread_mutex_unlock(&wq.wq_queue_lock);
947 952
948 pthread_mutex_lock(&wq.wq_queue_lock); 953 pthread_mutex_lock(&wq.wq_queue_lock);
949 while (wq.wq_alldone == 0) 954 while (wq.wq_alldone == 0)
950 pthread_cond_wait(&wq.wq_alldone_cv, &wq.wq_queue_lock); 955 pthread_cond_wait(&wq.wq_alldone_cv, &wq.wq_queue_lock);
951 pthread_mutex_unlock(&wq.wq_queue_lock); 956 pthread_mutex_unlock(&wq.wq_queue_lock);
952 957
953 join_threads(&wq); 958 join_threads(&wq);
954 959
955 /* 960 /*
956 * All requested files have been merged, with the resulting tree in 961 * All requested files have been merged, with the resulting tree in
957 * mstrtd. savetd is the tree that will be placed into the output file. 962 * mstrtd. savetd is the tree that will be placed into the output file.
958 * 963 *
959 * Regardless of whether we're doing a normal uniquification or an 964 * Regardless of whether we're doing a normal uniquification or an
960 * additive merge, we need a type tree that has been uniquified 965 * additive merge, we need a type tree that has been uniquified
961 * against uniqfile or withfile, as appropriate. 966 * against uniqfile or withfile, as appropriate.
962 * 967 *
963 * If we're doing a uniquification, we stuff the resulting tree into 968 * If we're doing a uniquification, we stuff the resulting tree into
964 * outfile. Otherwise, we add the tree to the tree already in withfile. 969 * outfile. Otherwise, we add the tree to the tree already in withfile.
965 */ 970 */
966 assert(fifo_len(wq.wq_queue) == 1); 971 assert(fifo_len(wq.wq_queue) == 1);
967 mstrtd = fifo_remove(wq.wq_queue); 972 mstrtd = fifo_remove(wq.wq_queue);
968 973
969 if (verbose || debug_level) { 974 if (verbose || debug_level) {
970 debug(2, "Statistics for td %p\n", (void *)mstrtd); 975 debug(2, "Statistics for td %p\n", (void *)mstrtd);
971 976
972 iidesc_stats(mstrtd->td_iihash); 977 iidesc_stats(mstrtd->td_iihash);
973 } 978 }
974 979
975 if (uniqfile != NULL || withfile != NULL) { 980 if (uniqfile != NULL || withfile != NULL) {
976 char *reffile, *reflabel = NULL; 981 char *reffile, *reflabel = NULL;
977 tdata_t *reftd; 982 tdata_t *reftd;
978 983
979 if (uniqfile != NULL) { 984 if (uniqfile != NULL) {
980 reffile = uniqfile; 985 reffile = uniqfile;
981 reflabel = uniqlabel; 986 reflabel = uniqlabel;
982 } else 987 } else
983 reffile = withfile; 988 reffile = withfile;
984 989
985 if (read_ctf(&reffile, 1, reflabel, read_ctf_save_cb, 990 if (read_ctf(&reffile, 1, reflabel, read_ctf_save_cb,
986 &reftd, require_ctf) == 0) { 991 &reftd, require_ctf) == 0) {
987 terminate("No CTF data found in reference file %s\n", 992 terminate("No CTF data found in reference file %s\n",
988 reffile); 993 reffile);
989 } 994 }
990 995
991 savetd = tdata_new(); 996 savetd = tdata_new();
992 997
993 if (CTF_TYPE_ISCHILD(reftd->td_nextid)) 998 if (CTF_TYPE_ISCHILD(reftd->td_nextid))
994 terminate("No room for additional types in master\n"); 999 terminate("No room for additional types in master\n");
995 1000
996 savetd->td_nextid = withfile ? reftd->td_nextid : 1001 savetd->td_nextid = withfile ? reftd->td_nextid :
997 CTF_INDEX_TO_TYPE(1, TRUE); 1002 CTF_INDEX_TO_TYPE(1, TRUE);
998 merge_into_master(mstrtd, reftd, savetd, 0); 1003 merge_into_master(mstrtd, reftd, savetd, 0);
999 1004
1000 tdata_label_add(savetd, label, CTF_LABEL_LASTIDX); 1005 tdata_label_add(savetd, label, CTF_LABEL_LASTIDX);
1001 1006
1002 if (withfile) { 1007 if (withfile) {
1003 /* 1008 /*
1004 * savetd holds the new data to be added to the withfile 1009 * savetd holds the new data to be added to the withfile
1005 */ 1010 */
1006 tdata_t *withtd = reftd; 1011 tdata_t *withtd = reftd;
1007 1012
1008 tdata_merge(withtd, savetd); 1013 tdata_merge(withtd, savetd);
1009 1014
1010 savetd = withtd; 1015 savetd = withtd;
1011 } else { 1016 } else {
1012 char uniqname[MAXPATHLEN]; 1017 char uniqname[MAXPATHLEN];
1013 labelent_t *parle; 1018 labelent_t *parle;
1014 1019
1015 parle = tdata_label_top(reftd); 1020 parle = tdata_label_top(reftd);
1016 1021
1017 savetd->td_parlabel = xstrdup(parle->le_name); 1022 savetd->td_parlabel = xstrdup(parle->le_name);
1018 1023
1019 strncpy(uniqname, reffile, sizeof (uniqname)); 1024 strncpy(uniqname, reffile, sizeof (uniqname));
1020 uniqname[MAXPATHLEN - 1] = '\0'; 1025 uniqname[MAXPATHLEN - 1] = '\0';
1021 savetd->td_parname = xstrdup(basename(uniqname)); 1026 savetd->td_parname = xstrdup(basename(uniqname));
1022 } 1027 }
1023 1028
1024 } else { 1029 } else {
1025 /* 1030 /*
1026 * No post processing. Write the merged tree as-is into the 1031 * No post processing. Write the merged tree as-is into the
1027 * output file. 1032 * output file.
1028 */ 1033 */
1029 tdata_label_free(mstrtd); 1034 tdata_label_free(mstrtd);
1030 tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX); 1035 tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);
1031 1036
1032 savetd = mstrtd; 1037 savetd = mstrtd;
1033 } 1038 }
1034 1039
1035 tmpname = mktmpname(outfile, ".ctf"); 1040 tmpname = mktmpname(outfile, ".ctf");
1036 write_ctf(savetd, outfile, tmpname, 1041 write_ctf(savetd, outfile, tmpname,
1037 CTF_COMPRESS | CTF_SWAP_BYTES | write_fuzzy_match | dynsym | keep_stabs); 1042 CTF_COMPRESS | CTF_SWAP_BYTES | write_fuzzy_match | dynsym | keep_stabs);
1038 if (rename(tmpname, outfile) != 0) 1043 if (rename(tmpname, outfile) != 0)
1039 terminate("Couldn't rename output temp file %s", tmpname); 1044 terminate("Couldn't rename output temp file %s", tmpname);
1040 free(tmpname); 1045 free(tmpname);
1041 1046
1042 return (0); 1047 return (0);
1043} 1048}