License header fixes
[lttng-tools.git] / src / bin / lttng / commands / add_context.c
CommitLineData
d65106b1
DG
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
d14d33bf
AM
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
d65106b1
DG
7 *
8 * This program 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. See the
11 * GNU General Public License for more details.
12 *
d14d33bf
AM
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
d65106b1
DG
16 */
17
18#define _GNU_SOURCE
90b9a268 19#include <ctype.h>
d65106b1
DG
20#include <popt.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <unistd.h>
27
3301e740
DG
28#include <urcu/list.h>
29
c399183f 30#include "../command.h"
d65106b1 31
b13d56d7
MD
32#define PRINT_LINE_LEN 80
33
d65106b1
DG
34static char *opt_event_name;
35static char *opt_channel_name;
5440dc42 36static char *opt_session_name;
55cc08a6 37static int opt_kernel;
d65106b1 38static int opt_userspace;
d78d6610
DG
39static char *opt_type;
40#if 0
41/* Not implemented yet */
eeac7d46 42static char *opt_cmd_name;
d65106b1 43static pid_t opt_pid;
d78d6610 44#endif
d65106b1
DG
45
46enum {
47 OPT_HELP = 1,
48 OPT_TYPE,
eeac7d46 49 OPT_USERSPACE,
679b4943 50 OPT_LIST_OPTIONS,
d65106b1
DG
51};
52
cd80958d
DG
53static struct lttng_handle *handle;
54
90b9a268
DG
55/*
56 * Taken from the LTTng ABI
57 */
58enum context_type {
59 CONTEXT_PID = 0,
60 CONTEXT_PERF_COUNTER = 1,
95da1297 61 CONTEXT_PROCNAME = 2,
90b9a268
DG
62 CONTEXT_PRIO = 3,
63 CONTEXT_NICE = 4,
64 CONTEXT_VPID = 5,
65 CONTEXT_TID = 6,
66 CONTEXT_VTID = 7,
67 CONTEXT_PPID = 8,
68 CONTEXT_VPPID = 9,
9197c5c4 69 CONTEXT_PTHREAD_ID = 10,
3301e740
DG
70};
71
90b9a268
DG
72/*
73 * Taken from the Perf ABI (all enum perf_*)
74 */
75enum perf_type {
76 PERF_TYPE_HARDWARE = 0,
77 PERF_TYPE_SOFTWARE = 1,
b13d56d7 78 PERF_TYPE_HW_CACHE = 3,
3301e740
DG
79};
80
90b9a268 81enum perf_count_hard {
b13d56d7
MD
82 PERF_COUNT_HW_CPU_CYCLES = 0,
83 PERF_COUNT_HW_INSTRUCTIONS = 1,
84 PERF_COUNT_HW_CACHE_REFERENCES = 2,
85 PERF_COUNT_HW_CACHE_MISSES = 3,
86 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
87 PERF_COUNT_HW_BRANCH_MISSES = 5,
88 PERF_COUNT_HW_BUS_CYCLES = 6,
89 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
90 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
90b9a268
DG
91};
92
93enum perf_count_soft {
94 PERF_COUNT_SW_CPU_CLOCK = 0,
95 PERF_COUNT_SW_TASK_CLOCK = 1,
96 PERF_COUNT_SW_PAGE_FAULTS = 2,
97 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
98 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
99 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
100 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
101 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
102 PERF_COUNT_SW_EMULATION_FAULTS = 8,
3301e740
DG
103};
104
b13d56d7
MD
105/*
106 * Generalized hardware cache events:
107 *
108 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
109 * { read, write, prefetch } x
110 * { accesses, misses }
111 */
112enum perf_hw_cache_id {
113 PERF_COUNT_HW_CACHE_L1D = 0,
114 PERF_COUNT_HW_CACHE_L1I = 1,
115 PERF_COUNT_HW_CACHE_LL = 2,
116 PERF_COUNT_HW_CACHE_DTLB = 3,
117 PERF_COUNT_HW_CACHE_ITLB = 4,
118 PERF_COUNT_HW_CACHE_BPU = 5,
119
120 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
121};
122
123enum perf_hw_cache_op_id {
124 PERF_COUNT_HW_CACHE_OP_READ = 0,
125 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
126 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
127
128 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
129};
130
131enum perf_hw_cache_op_result_id {
132 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
133 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
134
135 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
136};
137
d65106b1
DG
138static struct poptOption long_options[] = {
139 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
140 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
5440dc42 141 {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
d65106b1
DG
142 {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
143 {"event", 'e', POPT_ARG_STRING, &opt_event_name, 0, 0, 0},
144 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
d78d6610
DG
145#if 0
146 /* Not implemented yet */
d65106b1 147 {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0},
d78d6610
DG
148 {"userspace", 'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_cmd_name, OPT_USERSPACE, 0, 0},
149#else
150 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
151#endif
6caa2bcc 152 {"type", 't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
679b4943 153 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
d65106b1
DG
154 {0, 0, 0, 0, 0, 0, 0}
155};
156
90b9a268 157/*
b13d56d7 158 * Context options
90b9a268 159 */
b13d56d7
MD
160#define PERF_HW(opt, name) \
161 { \
162 "perf:" #opt, CONTEXT_PERF_COUNTER, \
163 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
164 }
90b9a268 165
b13d56d7
MD
166#define PERF_SW(opt, name) \
167 { \
168 "perf:" #opt, CONTEXT_PERF_COUNTER, \
169 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
170 }
90b9a268 171
b13d56d7
MD
172#define _PERF_HW_CACHE(optstr, name, op, result) \
173 { \
174 "perf:" optstr, CONTEXT_PERF_COUNTER, \
175 .u.perf = { \
176 PERF_TYPE_HW_CACHE, \
177 (uint64_t) PERF_COUNT_HW_CACHE_##name \
18829107
MD
178 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
179 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
b13d56d7
MD
180 }, \
181 }
182
183#define PERF_HW_CACHE(opt, name) \
184 _PERF_HW_CACHE(#opt "-loads", name, READ, ACCESS), \
185 _PERF_HW_CACHE(#opt "-load-misses", name, READ, MISS), \
186 _PERF_HW_CACHE(#opt "-stores", name, WRITE, ACCESS), \
187 _PERF_HW_CACHE(#opt "-store-misses", name, WRITE, MISS), \
188 _PERF_HW_CACHE(#opt "-prefetches", name, PREFETCH, ACCESS), \
189 _PERF_HW_CACHE(#opt "-prefetch-misses", name, PREFETCH, MISS) \
190
191static
192const struct ctx_opts {
90b9a268 193 char *symbol;
b13d56d7
MD
194 enum context_type ctx_type;
195 union {
196 struct {
197 uint32_t type;
198 uint64_t config;
199 } perf;
200 } u;
201} ctx_opts[] = {
202 { "pid", CONTEXT_PID },
95da1297 203 { "procname", CONTEXT_PROCNAME },
b13d56d7
MD
204 { "prio", CONTEXT_PRIO },
205 { "nice", CONTEXT_NICE },
206 { "vpid", CONTEXT_VPID },
207 { "tid", CONTEXT_TID },
9197c5c4 208 { "pthread_id", CONTEXT_PTHREAD_ID },
b13d56d7
MD
209 { "vtid", CONTEXT_VTID },
210 { "ppid", CONTEXT_PPID },
211 { "vppid", CONTEXT_VPPID },
212 /* Perf options */
213 PERF_HW(cpu-cycles, CPU_CYCLES),
214 PERF_HW(cycles, CPU_CYCLES),
215 PERF_HW(stalled-cycles-frontend, STALLED_CYCLES_FRONTEND),
216 PERF_HW(idle-cycles-frontend, STALLED_CYCLES_FRONTEND),
217 PERF_HW(stalled-cycles-backend, STALLED_CYCLES_BACKEND),
218 PERF_HW(idle-cycles-backend, STALLED_CYCLES_BACKEND),
219 PERF_HW(instructions, INSTRUCTIONS),
220 PERF_HW(cache-references, CACHE_REFERENCES),
221 PERF_HW(cache-misses, CACHE_MISSES),
222 PERF_HW(branch-instructions, BRANCH_INSTRUCTIONS),
223 PERF_HW(branches, BRANCH_INSTRUCTIONS),
224 PERF_HW(branch-misses, BRANCH_MISSES),
225 PERF_HW(bus-cycles, BUS_CYCLES),
226
227 PERF_HW_CACHE(L1-dcache, L1D),
228 PERF_HW_CACHE(L1-icache, L1I),
229 PERF_HW_CACHE(LLC, LL),
230 PERF_HW_CACHE(dTLB, DTLB),
231 _PERF_HW_CACHE("iTLB-loads", ITLB, READ, ACCESS),
232 _PERF_HW_CACHE("iTLB-load-misses", ITLB, READ, MISS),
233 _PERF_HW_CACHE("branch-loads", BPU, READ, ACCESS),
234 _PERF_HW_CACHE("branch-load-misses", BPU, READ, MISS),
235
236
237 PERF_SW(cpu-clock, CPU_CLOCK),
238 PERF_SW(task-clock, TASK_CLOCK),
239 PERF_SW(page-fault, PAGE_FAULTS),
240 PERF_SW(faults, PAGE_FAULTS),
241 PERF_SW(major-faults, PAGE_FAULTS_MAJ),
242 PERF_SW(minor-faults, PAGE_FAULTS_MIN),
243 PERF_SW(context-switches, CONTEXT_SWITCHES),
244 PERF_SW(cs, CONTEXT_SWITCHES),
245 PERF_SW(cpu-migrations, CPU_MIGRATIONS),
246 PERF_SW(migrations, CPU_MIGRATIONS),
247 PERF_SW(alignment-faults, ALIGNMENT_FAULTS),
248 PERF_SW(emulation-faults, EMULATION_FAULTS),
249 { NULL, -1 }, /* Closure */
90b9a268
DG
250};
251
b13d56d7
MD
252#undef PERF_SW
253#undef PERF_HW
254
90b9a268 255/*
b13d56d7 256 * Context type for command line option parsing.
90b9a268 257 */
b13d56d7
MD
258struct ctx_type {
259 const struct ctx_opts *opt;
260 struct cds_list_head list;
90b9a268
DG
261};
262
263/*
264 * List of context type. Use to enable multiple context on a single command
265 * line entry.
266 */
267struct ctx_type_list {
268 struct cds_list_head head;
269} ctx_type_list = {
270 .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
271};
272
90b9a268
DG
273/*
274 * Pretty print context type.
275 */
276static void print_ctx_type(FILE *ofp)
277{
b13d56d7
MD
278 const char *indent = " ";
279 int indent_len = strlen(indent);
280 int len, i = 0;
90b9a268 281
76e3c5dd 282 fprintf(ofp, "%s", indent);
b13d56d7 283 len = indent_len;
90b9a268 284 while (ctx_opts[i].symbol != NULL) {
b13d56d7
MD
285 if (len > indent_len) {
286 if (len + strlen(ctx_opts[i].symbol) + 2
287 >= PRINT_LINE_LEN) {
288 fprintf(ofp, ",\n");
76e3c5dd 289 fprintf(ofp, "%s", indent);
b13d56d7
MD
290 len = indent_len;
291 } else {
292 len += fprintf(ofp, ", ");
90b9a268
DG
293 }
294 }
b13d56d7 295 len += fprintf(ofp, "%s", ctx_opts[i].symbol);
90b9a268
DG
296 i++;
297 }
90b9a268
DG
298}
299
d65106b1
DG
300/*
301 * usage
302 */
303static void usage(FILE *ofp)
304{
b13d56d7 305 fprintf(ofp, "usage: lttng add-context -t TYPE\n");
d65106b1 306 fprintf(ofp, "\n");
b13d56d7 307 fprintf(ofp, "If no channel and no event is given (-c/-e), the context\n");
55cc08a6 308 fprintf(ofp, "will be added to all events and all channels.\n");
af87c45a
DG
309 fprintf(ofp, "Otherwise the context will be added only to the channel (-c)\n");
310 fprintf(ofp, "and/or event (-e) indicated.\n");
1256f150 311 fprintf(ofp, "Exactly one domain (-k/--kernel or -u/--userspace) must be specified.\n");
3301e740 312 fprintf(ofp, "\n");
d65106b1
DG
313 fprintf(ofp, "Options:\n");
314 fprintf(ofp, " -h, --help Show this help\n");
679b4943 315 fprintf(ofp, " --list-options Simple listing of options\n");
5eb00805
TD
316 fprintf(ofp, " -s, --session NAME Apply to session name\n");
317 fprintf(ofp, " -c, --channel NAME Apply to channel\n");
318 fprintf(ofp, " -e, --event NAME Apply to event\n");
af87c45a 319 fprintf(ofp, " -k, --kernel Apply to the kernel tracer\n");
d78d6610 320#if 0
af87c45a 321 fprintf(ofp, " -u, --userspace [CMD] Apply to the user-space tracer\n");
e14f64a8 322 fprintf(ofp, " If no CMD, the domain used is UST global\n");
5eb00805 323 fprintf(ofp, " otherwise the domain is UST EXEC_NAME\n");
e14f64a8 324 fprintf(ofp, " -p, --pid PID If -u, apply to specific PID (domain: UST PID)\n");
d78d6610 325#else
af87c45a 326 fprintf(ofp, " -u, --userspace Apply to the user-space tracer\n");
d78d6610 327#endif
b13d56d7 328 fprintf(ofp, " -t, --type TYPE Context type. You can repeat that option on\n");
af87c45a
DG
329 fprintf(ofp, " the command line to specify multiple contexts at once.\n");
330 fprintf(ofp, " (--kernel preempts --userspace)\n");
b13d56d7 331 fprintf(ofp, " TYPE can be one of the strings below:\n");
90b9a268 332 print_ctx_type(ofp);
d65106b1 333 fprintf(ofp, "\n");
90b9a268 334 fprintf(ofp, "Example:\n");
b13d56d7 335 fprintf(ofp, "This command will add the context information 'prio' and two perf\n"
af87c45a 336 "counters (hardware branch misses and cache misses), to all events\n"
b13d56d7
MD
337 "in the trace data output:\n");
338 fprintf(ofp, "# lttng add-context -k -t prio -t perf:branch-misses -t perf:cache-misses\n");
d65106b1
DG
339 fprintf(ofp, "\n");
340}
341
90b9a268
DG
342/*
343 * Find context numerical value from string.
344 */
345static int find_ctx_type_idx(const char *opt)
346{
347 int ret = -1, i = 0;
348
349 while (ctx_opts[i].symbol != NULL) {
350 if (strcmp(opt, ctx_opts[i].symbol) == 0) {
351 ret = i;
352 goto end;
353 }
354 i++;
355 }
356
357end:
358 return ret;
359}
360
90b9a268
DG
361/*
362 * Add context to channel or event.
d65106b1 363 */
cd80958d 364static int add_context(char *session_name)
d65106b1 365{
d16c1a4c 366 int ret = CMD_SUCCESS, warn = 0;
7d29a247
DG
367 struct lttng_event_context context;
368 struct lttng_domain dom;
3301e740 369 struct ctx_type *type;
b13d56d7 370 char *ptr;
d65106b1 371
441c16a7
MD
372 memset(&context, 0, sizeof(context));
373 memset(&dom, 0, sizeof(dom));
374
cd80958d
DG
375 if (opt_kernel) {
376 dom.type = LTTNG_DOMAIN_KERNEL;
d78d6610 377 } else if (opt_userspace) {
55cc08a6 378 dom.type = LTTNG_DOMAIN_UST;
55cc08a6 379 } else {
e14f64a8 380 ERR("Please specify a tracer (-k/--kernel or -u/--userspace)");
d16c1a4c 381 ret = CMD_ERROR;
55cc08a6 382 goto error;
cd80958d
DG
383 }
384
385 handle = lttng_create_handle(session_name, &dom);
386 if (handle == NULL) {
af87c45a 387 ret = CMD_ERROR;
cd80958d
DG
388 goto error;
389 }
390
5eb00805 391 /* Iterate over all the context types given */
3301e740 392 cds_list_for_each_entry(type, &ctx_type_list.head, list) {
b13d56d7
MD
393 context.ctx = type->opt->ctx_type;
394 if (context.ctx == LTTNG_EVENT_CONTEXT_PERF_COUNTER) {
395 context.u.perf_counter.type = type->opt->u.perf.type;
396 context.u.perf_counter.config = type->opt->u.perf.config;
d7b91b3c 397 strcpy(context.u.perf_counter.name, type->opt->symbol);
b13d56d7
MD
398 /* Replace : and - by _ */
399 while ((ptr = strchr(context.u.perf_counter.name, '-')) != NULL) {
400 *ptr = '_';
3301e740 401 }
b13d56d7
MD
402 while ((ptr = strchr(context.u.perf_counter.name, ':')) != NULL) {
403 *ptr = '_';
3301e740 404 }
3301e740 405 }
55cc08a6
DG
406 DBG("Adding context...");
407
408 ret = lttng_add_context(handle, &context, opt_event_name,
409 opt_channel_name);
410 if (ret < 0) {
b58471ff 411 ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
d16c1a4c 412 warn = 1;
55cc08a6 413 continue;
d65106b1 414 } else {
b58471ff
DG
415 if (opt_channel_name && opt_event_name) {
416 MSG("%s context %s added to event %s channel %s",
417 opt_kernel ? "kernel" : "UST", type->opt->symbol,
418 opt_channel_name, opt_event_name);
419 } else if (opt_channel_name && !opt_event_name) {
420 MSG("%s context %s added to channel %s",
421 opt_kernel ? "kernel" : "UST", type->opt->symbol,
422 opt_channel_name);
423 } else if (!opt_channel_name && opt_event_name) {
424 MSG("%s context %s added to event %s",
425 opt_kernel ? "kernel" : "UST", type->opt->symbol,
426 opt_event_name);
427 } else {
428 MSG("%s context %s added to all channels",
429 opt_kernel ? "kernel" : "UST", type->opt->symbol)
430 }
d65106b1 431 }
d65106b1
DG
432 }
433
af87c45a
DG
434 ret = CMD_SUCCESS;
435
d65106b1 436error:
cd80958d
DG
437 lttng_destroy_handle(handle);
438
d16c1a4c
DG
439 /*
440 * This means that at least one add_context failed and tells the user to
441 * look on stderr for error(s).
442 */
443 if (warn) {
444 ret = CMD_WARNING;
445 }
d65106b1
DG
446 return ret;
447}
448
449/*
5eb00805 450 * Add context to channel or event.
d65106b1
DG
451 */
452int cmd_add_context(int argc, const char **argv)
453{
90b9a268 454 int index, opt, ret = CMD_SUCCESS;
d65106b1 455 static poptContext pc;
b13d56d7 456 struct ctx_type *type, *tmptype;
cd80958d 457 char *session_name = NULL;
d65106b1 458
636167b6
DG
459 if (argc < 2) {
460 usage(stderr);
5eb00805 461 ret = CMD_ERROR;
636167b6
DG
462 goto end;
463 }
464
d65106b1
DG
465 pc = poptGetContext(NULL, argc, argv, long_options, 0);
466 poptReadDefaultConfig(pc, 0);
467
468 while ((opt = poptGetNextOpt(pc)) != -1) {
469 switch (opt) {
470 case OPT_HELP:
5eb00805 471 usage(stdout);
d65106b1
DG
472 goto end;
473 case OPT_TYPE:
af87c45a
DG
474 /*
475 * Look up the index of opt_type in ctx_opts[] first, so we don't
476 * have to free(type) on failure.
477 */
6caa2bcc 478 index = find_ctx_type_idx(opt_type);
b13d56d7 479 if (index < 0) {
6caa2bcc 480 ERR("Unknown context type %s", opt_type);
5eb00805 481 ret = CMD_ERROR;
b13d56d7 482 goto end;
90b9a268 483 }
5eb00805
TD
484
485 type = malloc(sizeof(struct ctx_type));
486 if (type == NULL) {
487 perror("malloc ctx_type");
488 ret = CMD_FATAL;
489 goto end;
490 }
491
b13d56d7
MD
492 type->opt = &ctx_opts[index];
493 if (type->opt->ctx_type == -1) {
6caa2bcc 494 ERR("Unknown context type %s", opt_type);
5eb00805
TD
495 free(type);
496 ret = CMD_ERROR;
497 goto end;
90b9a268
DG
498 } else {
499 cds_list_add(&type->list, &ctx_type_list.head);
500 }
d65106b1 501 break;
eeac7d46
MD
502 case OPT_USERSPACE:
503 opt_userspace = 1;
d78d6610 504#if 0
eeac7d46 505 opt_cmd_name = poptGetOptArg(pc);
d78d6610 506#endif
eeac7d46 507 break;
679b4943
SM
508 case OPT_LIST_OPTIONS:
509 list_cmd_options(stdout, long_options);
679b4943 510 goto end;
d65106b1
DG
511 default:
512 usage(stderr);
513 ret = CMD_UNDEFINED;
514 goto end;
515 }
516 }
517
ae856491
DG
518 if (!opt_type) {
519 ERR("Missing mandatory -t TYPE");
520 usage(stderr);
521 ret = CMD_ERROR;
522 goto end;
523 }
524
cd80958d
DG
525 if (!opt_session_name) {
526 session_name = get_session_name();
527 if (session_name == NULL) {
5eb00805 528 ret = CMD_ERROR;
cd80958d
DG
529 goto end;
530 }
531 } else {
532 session_name = opt_session_name;
533 }
534
535 ret = add_context(session_name);
3301e740 536
1256f150
DT
537 if (!opt_session_name) {
538 free(session_name);
539 }
540
5eb00805 541end:
3301e740 542 /* Cleanup allocated memory */
b13d56d7 543 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
3301e740
DG
544 free(type);
545 }
546
ca1c3607 547 poptFreeContext(pc);
d65106b1
DG
548 return ret;
549}
This page took 0.052 seconds and 4 git commands to generate.