少年修仙传客户端基础资源
hch
2024-04-01 d01413b00ef631ac20347716b23818b0b811f65f
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/**
 * \file
 * Runtime simple lock tracer
 *
 * Authors:
 *    Rodrigo Kumpera (rkumpera@novell.com)
 * 
 */
 
#include <config.h>
#include <stdio.h>
#include <string.h>
 
#include <sys/types.h>
 
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
 
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
 
#include <mono/utils/mono-compiler.h>
 
#include "lock-tracer.h"
 
/*
 * This is a very simple lock trace implementation. It can be used to verify that the runtime is
 * correctly following all locking rules.
 * 
 * To log more kind of locks just do the following:
 *     - add an entry into the RuntimeLocks enum
 *  - change mono_os_mutex_lock(mutex) to mono_locks_os_acquire (mutex, LockName)
 *  - change mono_os_mutex_unlock(mutex) to mono_locks_os_release (mutex, LockName)
 *  - change mono_coop_mutex_lock(mutex) to mono_locks_coop_acquire (mutex, LockName)
 *  - change mono_coop_mutex_unlock(mutex) to mono_locks_coop_release (mutex, LockName)
 *  - change the decoder to understand the new lock kind.
 *
 * TODO:
 *     - Use unbuffered IO without fsync
 *  - Switch to a binary log format
 *  - Enable tracing of more runtime locks
 *  - Add lock check assertions (must_not_hold_any_lock_but, must_hold_lock, etc)
 *   This should be used to verify methods that expect that a given lock is held at entrypoint, for example.
 * 
 * To use the trace, define LOCK_TRACER in lock-trace.h and when running mono define MONO_ENABLE_LOCK_TRACER.
 * This will produce a locks.ZZZ where ZZZ is the pid of the mono process.
 * Use the decoder to verify the result.
 */
 
#ifdef LOCK_TRACER
 
#ifdef TARGET_OSX
#include <dlfcn.h>
#endif
 
static FILE *trace_file;
static mono_mutex_t tracer_lock;
static size_t base_address;
 
typedef enum {
    RECORD_MUST_NOT_HOLD_ANY,
    RECORD_MUST_NOT_HOLD_ONE,
    RECORD_MUST_HOLD_ONE,
    RECORD_LOCK_ACQUIRED,
    RECORD_LOCK_RELEASED
} RecordType;
 
void
mono_locks_tracer_init (void)
{
    Dl_info info;
    int res;
    char *name;
    mono_os_mutex_init_recursive (&tracer_lock);
 
    if (!g_hasenv ("MONO_ENABLE_LOCK_TRACER"))
        return;
 
    name = g_strdup_printf ("locks.%d", getpid ());
    trace_file = fopen (name, "w+");
    g_free (name);
 
#ifdef TARGET_OSX
    res = dladdr ((void*)&mono_locks_tracer_init, &info);
    /* The 0x1000 offset was found by empirically trying it. */
    if (res)
        base_address = (size_t)info.dli_fbase - 0x1000;
#endif
}
 
 
#ifdef HAVE_EXECINFO_H
 
static int
mono_backtrace (gpointer array[], int traces)
{
    return backtrace (array, traces);
}
 
#else
 
static int
mono_backtrace (gpointer array[], int traces)
{
    return 0;
}
 
#endif
 
static void
add_record (RecordType record_kind, RuntimeLocks kind, gpointer lock)
{
    int i = 0;
    const int no_frames = 6;
    gpointer frames[no_frames];
 
    char *msg;
     if (!trace_file)
        return;
 
    memset (frames, 0, sizeof (gpointer) * no_frames);
    mono_backtrace (frames, no_frames);
    for (i = 0; i < no_frames; ++i)
        frames [i] = (gpointer)((size_t)frames[i] - base_address);
 
    /*We only dump 5 frames, which should be more than enough to most analysis.*/
    msg = g_strdup_printf ("%x,%d,%d,%p,%p,%p,%p,%p,%p\n", (guint32)mono_native_thread_id_get (), record_kind, kind, lock, frames [1], frames [2], frames [3], frames [4], frames [5]);
    fwrite (msg, strlen (msg), 1, trace_file);
    fflush (trace_file);
    g_free (msg);
}
 
void
mono_locks_lock_acquired (RuntimeLocks kind, gpointer lock)
{
    add_record (RECORD_LOCK_ACQUIRED, kind, lock);
}
 
void
mono_locks_lock_released (RuntimeLocks kind, gpointer lock)
{
    add_record (RECORD_LOCK_RELEASED, kind, lock);
}
#else
 
MONO_EMPTY_SOURCE_FILE (lock_tracer);
#endif /* LOCK_TRACER */