Browse code

cmdutils: wrap exit explicitly

Some C runtime implementations deadlock when calling threading functions
on the atexit() handler.

Use a simpler wrapper similar to av_log to call the cleanup function
before exit.

Bug-Id: 523

Luca Barbato authored on 2013/07/07 08:52:51
Showing 4 changed files
... ...
@@ -142,7 +142,7 @@ static int decode_interrupt_cb(void *ctx)
142 142
 
143 143
 const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
144 144
 
145
-static void exit_program(void)
145
+static void avconv_cleanup(int ret)
146 146
 {
147 147
     int i, j;
148 148
 
... ...
@@ -224,7 +224,7 @@ void assert_avoptions(AVDictionary *m)
224 224
     AVDictionaryEntry *t;
225 225
     if ((t = av_dict_get(m, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
226 226
         av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key);
227
-        exit(1);
227
+        exit_program(1);
228 228
     }
229 229
 }
230 230
 
... ...
@@ -239,7 +239,7 @@ static void abort_codec_experimental(AVCodec *c, int encoder)
239 239
     if (!(codec->capabilities & CODEC_CAP_EXPERIMENTAL))
240 240
         av_log(NULL, AV_LOG_FATAL, "Or use the non experimental %s '%s'.\n",
241 241
                codec_string, codec->name);
242
-    exit(1);
242
+    exit_program(1);
243 243
 }
244 244
 
245 245
 /*
... ...
@@ -333,14 +333,14 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
333 333
             new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
334 334
                                            av_buffer_default_free, NULL, 0);
335 335
             if (!new_pkt.buf)
336
-                exit(1);
336
+                exit_program(1);
337 337
         } else if (a < 0) {
338 338
             av_log(NULL, AV_LOG_ERROR, "%s failed for stream %d, codec %s",
339 339
                    bsfc->filter->name, pkt->stream_index,
340 340
                    avctx->codec ? avctx->codec->name : "copy");
341 341
             print_error("", a);
342 342
             if (exit_on_error)
343
-                exit(1);
343
+                exit_program(1);
344 344
         }
345 345
         *pkt = new_pkt;
346 346
 
... ...
@@ -355,7 +355,7 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
355 355
                ost->file_index, ost->st->index, ost->last_mux_dts, pkt->dts);
356 356
         if (exit_on_error) {
357 357
             av_log(NULL, AV_LOG_FATAL, "aborting.\n");
358
-            exit(1);
358
+            exit_program(1);
359 359
         }
360 360
         av_log(NULL, AV_LOG_WARNING, "changing to %"PRId64". This may result "
361 361
                "in incorrect timestamps in the output file.\n",
... ...
@@ -370,7 +370,7 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
370 370
     ret = av_interleaved_write_frame(s, pkt);
371 371
     if (ret < 0) {
372 372
         print_error("av_interleaved_write_frame()", ret);
373
-        exit(1);
373
+        exit_program(1);
374 374
     }
375 375
 }
376 376
 
... ...
@@ -404,7 +404,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
404 404
 
405 405
     if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
406 406
         av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
407
-        exit(1);
407
+        exit_program(1);
408 408
     }
409 409
 
410 410
     if (got_packet) {
... ...
@@ -436,7 +436,7 @@ static void do_subtitle_out(AVFormatContext *s,
436 436
     if (pts == AV_NOPTS_VALUE) {
437 437
         av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
438 438
         if (exit_on_error)
439
-            exit(1);
439
+            exit_program(1);
440 440
         return;
441 441
     }
442 442
 
... ...
@@ -468,7 +468,7 @@ static void do_subtitle_out(AVFormatContext *s,
468 468
                                                     subtitle_out_max_size, sub);
469 469
         if (subtitle_out_size < 0) {
470 470
             av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
471
-            exit(1);
471
+            exit_program(1);
472 472
         }
473 473
 
474 474
         av_init_packet(&pkt);
... ...
@@ -557,7 +557,7 @@ static void do_video_out(AVFormatContext *s,
557 557
         ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
558 558
         if (ret < 0) {
559 559
             av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
560
-            exit(1);
560
+            exit_program(1);
561 561
         }
562 562
 
563 563
         if (got_packet) {
... ...
@@ -601,7 +601,7 @@ static void do_video_stats(OutputStream *ost, int frame_size)
601 601
         vstats_file = fopen(vstats_filename, "w");
602 602
         if (!vstats_file) {
603 603
             perror("fopen");
604
-            exit(1);
604
+            exit_program(1);
605 605
         }
606 606
     }
607 607
 
... ...
@@ -912,7 +912,7 @@ static void flush_encoders(void)
912 912
                 ret = encode(enc, &pkt, NULL, &got_packet);
913 913
                 if (ret < 0) {
914 914
                     av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc);
915
-                    exit(1);
915
+                    exit_program(1);
916 916
                 }
917 917
                 *size += ret;
918 918
                 if (ost->logfile && enc->stats_out) {
... ...
@@ -1003,7 +1003,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
1003 1003
         if (av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, pkt->data, pkt->size, pkt->flags & AV_PKT_FLAG_KEY)) {
1004 1004
             opkt.buf = av_buffer_create(opkt.data, opkt.size, av_buffer_default_free, NULL, 0);
1005 1005
             if (!opkt.buf)
1006
-                exit(1);
1006
+                exit_program(1);
1007 1007
         }
1008 1008
     } else {
1009 1009
         opkt.data = pkt->data;
... ...
@@ -1073,7 +1073,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
1073 1073
             av_log(NULL, AV_LOG_FATAL, "Unable to find default channel "
1074 1074
                    "layout for Input Stream #%d.%d\n", ist->file_index,
1075 1075
                    ist->st->index);
1076
-            exit(1);
1076
+            exit_program(1);
1077 1077
         }
1078 1078
         decoded_frame->channel_layout = avctx->channel_layout;
1079 1079
 
... ...
@@ -1099,7 +1099,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
1099 1099
             if (ist_in_filtergraph(filtergraphs[i], ist) &&
1100 1100
                 configure_filtergraph(filtergraphs[i]) < 0) {
1101 1101
                 av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
1102
-                exit(1);
1102
+                exit_program(1);
1103 1103
             }
1104 1104
     }
1105 1105
 
... ...
@@ -1177,7 +1177,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
1177 1177
             if (ist_in_filtergraph(filtergraphs[i], ist) &&
1178 1178
                 configure_filtergraph(filtergraphs[i]) < 0) {
1179 1179
                 av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
1180
-                exit(1);
1180
+                exit_program(1);
1181 1181
             }
1182 1182
     }
1183 1183
 
... ...
@@ -1333,7 +1333,7 @@ static void print_sdp(void)
1333 1333
     AVFormatContext **avc = av_malloc(sizeof(*avc) * nb_output_files);
1334 1334
 
1335 1335
     if (!avc)
1336
-        exit(1);
1336
+        exit_program(1);
1337 1337
     for (i = 0; i < nb_output_files; i++)
1338 1338
         avc[i] = output_files[i]->ctx;
1339 1339
 
... ...
@@ -1424,7 +1424,7 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost,
1424 1424
     ost->forced_kf_pts   = av_malloc(sizeof(*ost->forced_kf_pts) * n);
1425 1425
     if (!ost->forced_kf_pts) {
1426 1426
         av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
1427
-        exit(1);
1427
+        exit_program(1);
1428 1428
     }
1429 1429
 
1430 1430
     p = kf;
... ...
@@ -1539,7 +1539,7 @@ static int transcode_init(void)
1539 1539
             case AVMEDIA_TYPE_AUDIO:
1540 1540
                 if (audio_volume != 256) {
1541 1541
                     av_log(NULL, AV_LOG_FATAL, "-acodec copy and -vol are incompatible (frames are not decoded)\n");
1542
-                    exit(1);
1542
+                    exit_program(1);
1543 1543
                 }
1544 1544
                 codec->channel_layout     = icodec->channel_layout;
1545 1545
                 codec->sample_rate        = icodec->sample_rate;
... ...
@@ -1619,7 +1619,7 @@ static int transcode_init(void)
1619 1619
                     fg = init_simple_filtergraph(ist, ost);
1620 1620
                     if (configure_filtergraph(fg)) {
1621 1621
                         av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n");
1622
-                        exit(1);
1622
+                        exit_program(1);
1623 1623
                     }
1624 1624
             }
1625 1625
 
... ...
@@ -1677,7 +1677,7 @@ static int transcode_init(void)
1677 1677
                         if (!f) {
1678 1678
                             av_log(NULL, AV_LOG_FATAL, "Cannot write log file '%s' for pass-1 encoding: %s\n",
1679 1679
                                    logfilename, strerror(errno));
1680
-                            exit(1);
1680
+                            exit_program(1);
1681 1681
                         }
1682 1682
                         ost->logfile = f;
1683 1683
                     } else {
... ...
@@ -1686,7 +1686,7 @@ static int transcode_init(void)
1686 1686
                         if (cmdutils_read_file(logfilename, &logbuffer, &logbuffer_size) < 0) {
1687 1687
                             av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
1688 1688
                                    logfilename);
1689
-                            exit(1);
1689
+                            exit_program(1);
1690 1690
                         }
1691 1691
                         codec->stats_in = logbuffer;
1692 1692
                     }
... ...
@@ -2090,7 +2090,7 @@ static int process_input(void)
2090 2090
         if (ret != AVERROR_EOF) {
2091 2091
             print_error(is->filename, ret);
2092 2092
             if (exit_on_error)
2093
-                exit(1);
2093
+                exit_program(1);
2094 2094
         }
2095 2095
         ifile->eof_reached = 1;
2096 2096
 
... ...
@@ -2158,7 +2158,7 @@ static int process_input(void)
2158 2158
         av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d\n",
2159 2159
                ist->file_index, ist->st->index);
2160 2160
         if (exit_on_error)
2161
-            exit(1);
2161
+            exit_program(1);
2162 2162
     }
2163 2163
 
2164 2164
 discard_packet:
... ...
@@ -2329,7 +2329,7 @@ int main(int argc, char **argv)
2329 2329
     int ret;
2330 2330
     int64_t ti;
2331 2331
 
2332
-    atexit(exit_program);
2332
+    register_exit(avconv_cleanup);
2333 2333
 
2334 2334
     av_log_set_flags(AV_LOG_SKIP_REPEATED);
2335 2335
     parse_loglevel(argc, argv, options);
... ...
@@ -2347,29 +2347,29 @@ int main(int argc, char **argv)
2347 2347
     /* parse options and open all input/output files */
2348 2348
     ret = avconv_parse_options(argc, argv);
2349 2349
     if (ret < 0)
2350
-        exit(1);
2350
+        exit_program(1);
2351 2351
 
2352 2352
     if (nb_output_files <= 0 && nb_input_files == 0) {
2353 2353
         show_usage();
2354 2354
         av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
2355
-        exit(1);
2355
+        exit_program(1);
2356 2356
     }
2357 2357
 
2358 2358
     /* file converter / grab */
2359 2359
     if (nb_output_files <= 0) {
2360 2360
         fprintf(stderr, "At least one output file must be specified\n");
2361
-        exit(1);
2361
+        exit_program(1);
2362 2362
     }
2363 2363
 
2364 2364
     ti = getutime();
2365 2365
     if (transcode() < 0)
2366
-        exit(1);
2366
+        exit_program(1);
2367 2367
     ti = getutime() - ti;
2368 2368
     if (do_benchmark) {
2369 2369
         int maxrss = getmaxrss() / 1024;
2370 2370
         printf("bench: utime=%0.3fs maxrss=%ikB\n", ti / 1000000.0, maxrss);
2371 2371
     }
2372 2372
 
2373
-    exit(0);
2373
+    exit_program(0);
2374 2374
     return 0;
2375 2375
 }
... ...
@@ -60,7 +60,7 @@ static const char unit_hertz_str[]          = "Hz"   ;
60 60
 static const char unit_byte_str[]           = "byte" ;
61 61
 static const char unit_bit_per_second_str[] = "bit/s";
62 62
 
63
-static void exit_program(void)
63
+static void avprobe_cleanup(int ret)
64 64
 {
65 65
     av_dict_free(&fmt_entries_to_show);
66 66
 }
... ...
@@ -366,7 +366,7 @@ static void probe_group_enter(const char *name, int type)
366 366
 
367 367
     if (!octx.prefix || !name) {
368 368
         fprintf(stderr, "Out of memory\n");
369
-        exit(1);
369
+        exit_program(1);
370 370
     }
371 371
 
372 372
     if (octx.level) {
... ...
@@ -854,7 +854,7 @@ static void opt_input_file(void *optctx, const char *arg)
854 854
         fprintf(stderr,
855 855
                 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
856 856
                 arg, input_filename);
857
-        exit(1);
857
+        exit_program(1);
858 858
     }
859 859
     if (!strcmp(arg, "-"))
860 860
         arg = "pipe:";
... ...
@@ -919,7 +919,7 @@ int main(int argc, char **argv)
919 919
     if (!buffer)
920 920
         exit(1);
921 921
 
922
-    atexit(exit_program);
922
+    register_exit(avprobe_cleanup);
923 923
 
924 924
     options = real_options;
925 925
     parse_loglevel(argc, argv, options);
... ...
@@ -949,13 +949,13 @@ int main(int argc, char **argv)
949 949
         fprintf(stderr,
950 950
                 "Use -h to get full help or, even better, run 'man %s'.\n",
951 951
                 program_name);
952
-        exit(1);
952
+        exit_program(1);
953 953
     }
954 954
 
955 955
     probe_out = avio_alloc_context(buffer, AVP_BUFFSIZE, 1, NULL, NULL,
956 956
                                  probe_buf_write, NULL);
957 957
     if (!probe_out)
958
-        exit(1);
958
+        exit_program(1);
959 959
 
960 960
     probe_header();
961 961
     ret = probe_file(input_filename);
... ...
@@ -82,6 +82,21 @@ void log_callback_help(void *ptr, int level, const char *fmt, va_list vl)
82 82
     vfprintf(stdout, fmt, vl);
83 83
 }
84 84
 
85
+static void (*program_exit)(int ret);
86
+
87
+void register_exit(void (*cb)(int ret))
88
+{
89
+    program_exit = cb;
90
+}
91
+
92
+void exit_program(int ret)
93
+{
94
+    if (program_exit)
95
+        program_exit(ret);
96
+
97
+    exit(ret);
98
+}
99
+
85 100
 double parse_number_or_die(const char *context, const char *numstr, int type,
86 101
                            double min, double max)
87 102
 {
... ...
@@ -99,7 +114,7 @@ double parse_number_or_die(const char *context, const char *numstr, int type,
99 99
     else
100 100
         return d;
101 101
     av_log(NULL, AV_LOG_FATAL, error, context, numstr, min, max);
102
-    exit(1);
102
+    exit_program(1);
103 103
     return 0;
104 104
 }
105 105
 
... ...
@@ -110,7 +125,7 @@ int64_t parse_time_or_die(const char *context, const char *timestr,
110 110
     if (av_parse_time(&us, timestr, is_duration) < 0) {
111 111
         av_log(NULL, AV_LOG_FATAL, "Invalid %s specification for %s: %s\n",
112 112
                is_duration ? "duration" : "date", context, timestr);
113
-        exit(1);
113
+        exit_program(1);
114 114
     }
115 115
     return us;
116 116
 }
... ...
@@ -272,7 +287,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
272 272
         }
273 273
     }
274 274
     if (po->flags & OPT_EXIT)
275
-        exit(0);
275
+        exit_program(0);
276 276
 
277 277
     return 0;
278 278
 }
... ...
@@ -332,7 +347,7 @@ void parse_options(void *optctx, int argc, char **argv, const OptionDef *options
332 332
             opt++;
333 333
 
334 334
             if ((ret = parse_option(optctx, opt, argv[optindex], options)) < 0)
335
-                exit(1);
335
+                exit_program(1);
336 336
             optindex += ret;
337 337
         } else {
338 338
             if (parse_arg_function)
... ...
@@ -538,7 +553,7 @@ static void init_parse_context(OptionParseContext *octx,
538 538
     octx->nb_groups = nb_groups;
539 539
     octx->groups    = av_mallocz(sizeof(*octx->groups) * octx->nb_groups);
540 540
     if (!octx->groups)
541
-        exit(1);
541
+        exit_program(1);
542 542
 
543 543
     for (i = 0; i < octx->nb_groups; i++)
544 544
         octx->groups[i].group_def = &groups[i];
... ...
@@ -705,7 +720,7 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg)
705 705
                "Possible levels are numbers or:\n", arg);
706 706
         for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++)
707 707
             av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name);
708
-        exit(1);
708
+        exit_program(1);
709 709
     }
710 710
     av_log_set_level(level);
711 711
     return 0;
... ...
@@ -1586,13 +1601,13 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
1586 1586
 {
1587 1587
     if (new_size >= INT_MAX / elem_size) {
1588 1588
         av_log(NULL, AV_LOG_ERROR, "Array too big.\n");
1589
-        exit(1);
1589
+        exit_program(1);
1590 1590
     }
1591 1591
     if (*size < new_size) {
1592 1592
         uint8_t *tmp = av_realloc(array, new_size*elem_size);
1593 1593
         if (!tmp) {
1594 1594
             av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n");
1595
-            exit(1);
1595
+            exit_program(1);
1596 1596
         }
1597 1597
         memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);
1598 1598
         *size = new_size;
... ...
@@ -45,6 +45,16 @@ extern struct SwsContext *sws_opts;
45 45
 extern AVDictionary *format_opts, *codec_opts, *resample_opts;
46 46
 
47 47
 /**
48
+ * Register a program-specific cleanup routine.
49
+ */
50
+void register_exit(void (*cb)(int ret));
51
+
52
+/**
53
+ * Wraps exit with a program-specific cleanup routine.
54
+ */
55
+void exit_program(int ret);
56
+
57
+/**
48 58
  * Initialize the cmdutils option system, in particular
49 59
  * allocate the *_opts contexts.
50 60
  */