mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-12 20:34:19 +00:00
Add MR_strerror as a thread-safe alternative to strerror. The current implementation wraps strerror_r(), strerror_s() or sys_errlist as appropriate for the platform. Bug #340. configure.ac: runtime/mercury_conf.h.in: Check for strerror_r, strerror_s. Delete irrelevant code in the sockets test for the external debugger. runtime/mercury_runtime_util.c: runtime/mercury_runtime_util.h: Add MR_strerror and use it. library/io.m: Use MR_strerror. In particular, mercury_output_error was not thread-safe. Pass errno to mercury_output_error explicitly for clarity. Delete req_lock parameter in ML_maybe_make_err_msg macro which is not needed any more. compiler/prog_event.m: runtime/mercury_deep_profiling.c: runtime/mercury_misc.c: runtime/mercury_term_size.c: runtime/mercury_trace_base.c: trace/mercury_trace_cmd_developer.c: trace/mercury_trace_cmd_exp.c: trace/mercury_trace_cmd_misc.c: trace/mercury_trace_declarative.c: trace/mercury_trace_external.c: trace/mercury_trace_internal.c: Use MR_strerror. compiler/notes/coding_standards.html: Update coding standard. extras/net/sockets.m: extras/net/tcp.m: Use MR_strerror. NEWS: Announce change.
166 lines
3.6 KiB
C
166 lines
3.6 KiB
C
/*
|
|
** vim: ts=4 sw=4 expandtab
|
|
*/
|
|
/*
|
|
** Copyright (C) 1996-2000,2002, 2006, 2010-2011 The University of Melbourne.
|
|
** This file may only be copied under the terms of the GNU Library General
|
|
** Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
*/
|
|
|
|
#include "mercury_conf.h"
|
|
#ifndef MR_HIGHLEVEL_CODE
|
|
#include "mercury_imp.h"
|
|
#endif
|
|
#include "mercury_string.h"
|
|
#include "mercury_misc.h"
|
|
#include "mercury_array_macros.h"
|
|
#include "mercury_runtime_util.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <errno.h>
|
|
|
|
static void MR_print_warning(const char *prog, const char *fmt, va_list args);
|
|
static void MR_do_perror(const char *prog, const char *message);
|
|
|
|
void
|
|
MR_warning(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
MR_print_warning("Mercury runtime", fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void
|
|
MR_mdb_warning(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
MR_print_warning("mdb", fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
static void
|
|
MR_print_warning(const char *prog, const char *fmt, va_list args)
|
|
{
|
|
fflush(stdout); /* in case stdout and stderr are the same */
|
|
|
|
fprintf(stderr, "%s: ", prog);
|
|
vfprintf(stderr, fmt, args);
|
|
fprintf(stderr, "\n");
|
|
|
|
fflush(stderr);
|
|
}
|
|
|
|
void
|
|
MR_perror(const char *message)
|
|
{
|
|
MR_do_perror("Mercury runtime", message);
|
|
}
|
|
|
|
void
|
|
MR_mdb_perror(const char *message)
|
|
{
|
|
MR_do_perror("mdb", message);
|
|
}
|
|
|
|
static void
|
|
MR_do_perror(const char *prog, const char *message)
|
|
{
|
|
int saved_errno;
|
|
|
|
saved_errno = errno;
|
|
fflush(stdout); /* in case stdout and stderr are the same */
|
|
|
|
fprintf(stderr, "%s: ", prog);
|
|
errno = saved_errno;
|
|
perror(message);
|
|
}
|
|
|
|
/*
|
|
** XXX will need to modify this to kill other threads if MR_THREAD_SAFE
|
|
** (and cleanup resources, etc....)
|
|
*/
|
|
|
|
void
|
|
MR_fatal_error(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int error = errno;
|
|
char errbuf[MR_STRERROR_BUF_SIZE];
|
|
|
|
fflush(stdout); /* in case stdout and stderr are the same */
|
|
|
|
if (error != 0) {
|
|
fprintf(stderr, "Errno = %d: %s\n", error,
|
|
MR_strerror(error, errbuf, sizeof(errbuf)));
|
|
}
|
|
fprintf(stderr, "Mercury runtime: ");
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
fprintf(stderr, "\n");
|
|
|
|
#ifndef MR_HIGHLEVEL_CODE
|
|
MR_trace_report(stderr);
|
|
#endif
|
|
|
|
fflush(NULL); /* flushes all stdio output streams */
|
|
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void
|
|
MR_external_fatal_error(const char *locn, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
|
|
fflush(stdout); /* in case stdout and stderr are the same */
|
|
|
|
fprintf(stderr, "%s: ", locn);
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
fprintf(stderr, "\n");
|
|
|
|
#ifndef MR_HIGHLEVEL_CODE
|
|
MR_trace_report(stderr);
|
|
#endif
|
|
|
|
fflush(NULL); /* flushes all stdio output streams */
|
|
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
typedef struct {
|
|
void (*func)(void *);
|
|
void *data;
|
|
} MR_cleanup_record;
|
|
|
|
static MR_cleanup_record *MR_cleanup_records = NULL;
|
|
static int MR_cleanup_record_next = 0;
|
|
static int MR_cleanup_record_max = 0;
|
|
|
|
#define INIT_CLEANUP_RECORD_ARRAY_SIZE 10
|
|
|
|
void
|
|
MR_register_exception_cleanup(void (*func)(void *), void *data)
|
|
{
|
|
MR_ensure_room_for_next(MR_cleanup_record, MR_cleanup_record,
|
|
INIT_CLEANUP_RECORD_ARRAY_SIZE);
|
|
MR_cleanup_records[MR_cleanup_record_next].func = func;
|
|
MR_cleanup_records[MR_cleanup_record_next].data = data;
|
|
MR_cleanup_record_next++;
|
|
}
|
|
|
|
void
|
|
MR_perform_registered_exception_cleanups(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MR_cleanup_record_next; i++) {
|
|
MR_cleanup_records[i].func(MR_cleanup_records[i].data);
|
|
}
|
|
}
|