-
Notifications
You must be signed in to change notification settings - Fork 0
/
logevt.c
198 lines (168 loc) · 4.23 KB
/
logevt.c
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
* SPDX-License-Identifier: GPL-2.0
* Copyright (C) 2005-2022 Dahetral Systems
* Author: David Turvene ([email protected])
*
* Copy the ringbuffer pattern in ringbuffer.c for an event logger.
*/
#include <stdio.h> /* char I/O, perror */
#include <time.h> /* clock_gettime */
#include <stdint.h> /* uint32_t, etc. */
#include <string.h> /* strcpy */
#include "logevt.h" /* enums and external function prototypes */
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
/**
* define the logrec, typedef to buf_t
*/
typedef struct logrec {
evtid_t id;
uint32_t val;
struct timespec tstamp;
} buf_t;
/* make this large to capture all events */
#define LOG_QDEPTH 10000
/**
* struct qlog - ringbuffer context for logger
*
* This is a hacky cut-and-paste of the test code (struct sq). Only difference
* is the name and the statically allocated bufs array size.
*
* Probably should refactor both ringbuffer structures into a generic one and
* then have convert bufs to a pointer, which can point to a custom statically
* allocated array.
*/
typedef struct qlog {
buf_t bufs[LOG_QDEPTH];
buf_t *enq;
buf_t *deq;
int32_t count;
buf_t *first;
buf_t *last;
int32_t max;
void (*cb)(const buf_t *);
} qlog_t;
/**
* instantiate the event logger ringbuffer, same pattern as simple queue
*/
static qlog_t logevt = {
.enq = logevt.bufs,
.deq = logevt.bufs,
.count = 0,
.first = logevt.bufs,
.last = &logevt.bufs[ARRAY_SIZE(logevt.bufs)-1],
.max = ARRAY_SIZE(logevt.bufs),
};
/**
* evt_enq - enqueue a log element
* @id: the event id enum defined in logevt.h
* @val: value to write to bufs element
*
* write a logger record using the event id enum and value
* use gettime for timestamp and write that also.
* Other than that, same logic as ringbuffer q_enq
*/
void evt_enq(evtid_t id, uint32_t val)
{
struct timespec ts;
/* get clock before mutex because expensive, resulting in
* calling pthread stalling
*/
clock_gettime(CLOCK_MONOTONIC, &ts);
pthread_mutex_lock(&log_mutex);
/* if enq (newest) is about to overwrite the deq (oldest) location
* then move deq to next oldest before overwriting, if last element
* then move deq to first element.
*/
if (logevt.count == logevt.max && logevt.enq == logevt.deq) {
if (logevt.deq == logevt.last)
logevt.deq = logevt.first;
else
logevt.deq++;
}
logevt.enq->id = id;
logevt.enq->val = val;
logevt.enq->tstamp.tv_sec = ts.tv_sec;
logevt.enq->tstamp.tv_nsec = ts.tv_nsec;
if (logevt.count < logevt.max)
logevt.count++;
/* if last bufs, set to first
* otherwise increment to next bufs element
*/
if (logevt.enq == logevt.last)
logevt.enq = logevt.first;
else
logevt.enq++;
pthread_mutex_unlock(&log_mutex);
}
/**
* evt_deq - dequeue a log element
* @recp: pointer to a current bufs element
*
* read a logger record. Same logic as ringbuffer q_deq
*
* Return:
* same as q_deq, 0 for success and negative otherwise
*/
int evt_deq(buf_t *recp)
{
if (logevt.count == 0)
return(-1);
pthread_mutex_lock(&log_mutex);
*recp = *(logevt.deq);
logevt.count--;
if (logevt.deq == logevt.last)
logevt.deq = logevt.first;
else
logevt.deq++;
pthread_mutex_unlock(&log_mutex);
return(0);
}
/**
* print_evts - dequeue all logger elements and write to stdout
*
*/
#define TV_FMT "%ld.%06ld"
void print_evts(void) {
buf_t rec;
int idx = 0;
char evtid[32];
char evtval[32];
printf("dumping log\n");
/* loop until all events are dequeued
* starting from oldest and ending at newest
*/
while (0 == evt_deq(&rec)) {
/* convert record id (event type enum) to a string */
switch(rec.id) {
case EVT_ENQ:
strcpy(evtid, "enq");
break;
case EVT_DEQ:
strcpy(evtid, "deq");
break;
case EVT_DEQ_IDLE:
strcpy(evtid, "deq rb empty");
break;
default:
strcpy(evtid, "???");
break;
}
/* convert val to a string */
switch(rec.val) {
case 0xdeadbeef:
strcpy(evtval, "END_EL");
break;
default:
sprintf(evtval, "val=%u", rec.val);
break;
}
printf("%d: %s %s time=" TV_FMT "\n",
idx++,
evtid,
evtval,
rec.tstamp.tv_sec,
rec.tstamp.tv_nsec);
}
fprintf(stderr, "total log records = %d\n", idx);
}