summaryrefslogtreecommitdiff
path: root/rts/eventlog/EventLogWriter.c
blob: 9f6f487d8e4ed8135addb245faa20accfa129358 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team, 2008-2009
 *
 * Support for fast binary event logging.
 *
 * ---------------------------------------------------------------------------*/

#include "PosixSource.h"
#include "Rts.h"

#include "RtsUtils.h"
#include "rts/EventLogWriter.h"

#include <string.h>
#include <stdio.h>
#include <fs_rts.h>
#if defined(HAVE_SYS_TYPES_H)
#include <sys/types.h>
#endif
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

// PID of the process that writes to event_log_filename (#4512)
static pid_t event_log_pid = -1;

// File for logging events
static FILE *event_log_file = NULL;

static void initEventLogFileWriter(void);
static bool writeEventLogFile(void *eventlog, size_t eventlog_size);
static void flushEventLogFile(void);
static void stopEventLogFileWriter(void);

static char *outputFileName(void)
{

    if (RtsFlags.TraceFlags.trace_output) {
        return strdup(RtsFlags.TraceFlags.trace_output);
    } else {
        char *prog = stgMallocBytes(strlen(prog_name) + 1,
                                    "initEventLogFileWriter");
        strcpy(prog, prog_name);
#if defined(mingw32_HOST_OS)
        // on Windows, drop the .exe suffix if there is one
        {
            char *suff;
            suff = strrchr(prog,'.');
            if (suff != NULL && !strcmp(suff,".exe")) {
                *suff = '\0';
            }
        }
#endif
        char *filename = stgMallocBytes(strlen(prog)
                                        + 10 /* .%d */
                                        + 10 /* .eventlog */,
                                        "initEventLogFileWriter");

        if (event_log_pid == -1) { // #4512
            // Single process
            sprintf(filename, "%s.eventlog", prog);
            event_log_pid = getpid();
        } else {
            // Forked process, eventlog already started by the parent
            // before fork
            event_log_pid = getpid();
            // We don't have a FMT* symbol for pid_t, so we go via Word64
            // to be sure of not losing range. It would be nicer to have a
            // FMT* symbol or similar, though.
            sprintf(filename, "%s.%" FMT_Word64 ".eventlog",
                    prog, (StgWord64)event_log_pid);
        }
        stgFree(prog);
        return filename;
    }
}

static void
initEventLogFileWriter(void)
{
    char *event_log_filename = outputFileName();

    /* Open event log file for writing. */
    if ((event_log_file = __rts_fopen(event_log_filename, "wb")) == NULL) {
        sysErrorBelch(
            "initEventLogFileWriter: can't open %s", event_log_filename);
        stg_exit(EXIT_FAILURE);
    }

    stgFree(event_log_filename);
}

static bool
writeEventLogFile(void *eventlog, size_t eventlog_size)
{
    unsigned char *begin = eventlog;
    size_t remain = eventlog_size;

    while (remain > 0) {
        size_t written = fwrite(begin, 1, remain, event_log_file);
        if (written == 0) {
            return false;
        }
        remain -= written;
        begin += written;
    }

    return true;
}

static void
flushEventLogFile(void)
{
    if (event_log_file != NULL) {
        fflush(event_log_file);
    }
}

static void
stopEventLogFileWriter(void)
{
    if (event_log_file != NULL) {
        fclose(event_log_file);
    }
}

const EventLogWriter FileEventLogWriter = {
    .initEventLogWriter = initEventLogFileWriter,
    .writeEventLog = writeEventLogFile,
    .flushEventLog = flushEventLogFile,
    .stopEventLogWriter = stopEventLogFileWriter
};