VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/log/tracelogwriter.cpp@ 78098

Last change on this file since 78098 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.9 KB
Line 
1/* $Id: tracelogwriter.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - Trace log writer.
4 */
5
6/*
7 * Copyright (C) 2018-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/formats/tracelog.h>
33#include <iprt/tracelog.h>
34
35
36#include <iprt/avl.h>
37#include <iprt/asm.h>
38#include <iprt/assert.h>
39#include <iprt/err.h>
40#include <iprt/file.h>
41#include <iprt/log.h>
42#include <iprt/mem.h>
43#include <iprt/semaphore.h>
44#include <iprt/string.h>
45#include <iprt/tcp.h>
46#include <iprt/time.h>
47
48#include "internal/magics.h"
49
50
51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54
55
56/**
57 * Trace log writer internal event descriptor.
58 */
59typedef struct RTTRACELOGWREVTDESC
60{
61 /** AVL node core data */
62 AVLPVNODECORE Core;
63 /** The ID associated with this event descriptor. */
64 uint32_t u32Id;
65 /** Overall size of the event data not counting variable raw data items. */
66 size_t cbEvtData;
67 /** Number of non static raw binary items in the descriptor. */
68 uint32_t cRawDataNonStatic;
69 /** Pointer to the scratch event data buffer when adding events. */
70 uint8_t *pbEvt;
71 /** Embedded event descriptor. */
72 RTTRACELOGEVTDESC EvtDesc;
73 /** Array of event item descriptors, variable in size. */
74 RTTRACELOGEVTITEMDESC aEvtItemDesc[1];
75} RTTRACELOGWREVTDESC;
76/** Pointer to internal trace log writer event descriptor. */
77typedef RTTRACELOGWREVTDESC *PRTTRACELOGWREVTDESC;
78/** Pointer to const internal trace log writer event descriptor. */
79typedef const RTTRACELOGWREVTDESC *PCRTTRACELOGWREVTDESC;
80
81
82/**
83 * Trace log writer instance data.
84 */
85typedef struct RTTRACELOGWRINT
86{
87 /** Magic for identification. */
88 uint32_t u32Magic;
89 /** Stream out callback. */
90 PFNRTTRACELOGWRSTREAM pfnStreamOut;
91 /** Stream close callback .*/
92 PFNRTTRACELOGSTREAMCLOSE pfnStreamClose;
93 /** Opaque user data passed to the stream callback. */
94 void *pvUser;
95 /** Mutex protecting the structure. */
96 RTSEMMUTEX hMtx;
97 /** Next sequence number to use. */
98 volatile uint64_t u64SeqNoNext;
99 /** Pointer to the description if set. */
100 char *pszDesc;
101 /** AVL tree root for event descriptor lookups. */
102 AVLPVTREE pTreeEvtDescs;
103 /** Number of event descriptors known. */
104 uint32_t cEvtDescs;
105} RTTRACELOGWRINT;
106/** Pointer to a trace log writer instance. */
107typedef RTTRACELOGWRINT *PRTTRACELOGWRINT;
108
109
110/**
111 * The TCP server/client state.
112 */
113typedef struct RTTRACELOGWRTCP
114{
115 /** Flag whether this is a server or client instance. */
116 bool fIsServer;
117 /** The TCP socket handle for the connection. */
118 RTSOCKET hSock;
119 /** The TCP server. */
120 PRTTCPSERVER pTcpSrv;
121} RTTRACELOGWRTCP;
122/** Pointer to a TCP server/client state. */
123typedef RTTRACELOGWRTCP *PRTTRACELOGWRTCP;
124
125
126/*********************************************************************************************************************************
127* Defined Constants And Macros *
128*********************************************************************************************************************************/
129
130
131/**
132 * Returns the size required for the internal event descriptor representation.
133 *
134 * @returns Number of bytes required.
135 * @param pEvtDesc Pointer to the external descriptor.
136 */
137static size_t rtTraceLogWrtEvtDescGetSz(PCRTTRACELOGEVTDESC pEvtDesc)
138{
139 size_t cbAlloc = RT_UOFFSETOF_DYN(RTTRACELOGWREVTDESC, aEvtItemDesc[pEvtDesc->cEvtItems]);
140
141 cbAlloc += strlen(pEvtDesc->pszId) + 1;
142 if (pEvtDesc->pszDesc)
143 cbAlloc += strlen(pEvtDesc->pszDesc) + 1;
144 for (unsigned i = 0; i < pEvtDesc->cEvtItems; i++)
145 {
146 PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDesc->paEvtItemDesc[i];
147
148 cbAlloc += strlen(pEvtItemDesc->pszName) + 1;
149 if (pEvtItemDesc->pszDesc)
150 cbAlloc += strlen(pEvtItemDesc->pszDesc) + 1;
151 }
152
153 return cbAlloc;
154}
155
156
157/**
158 * Copies a string into a supplied buffer assigning the start to the given string pointer.
159 *
160 * @returns Pointer to the memory after the destination buffer holding the string.
161 * @param ppsz Where to store the pointer to the start of the string.
162 * @param pszTo Where to copy the string including the temrinator to.
163 * @param pszFrom The string to copy.
164 */
165DECLINLINE(char *) rtTraceLogWrCopyStr(const char **ppsz, char *pszTo, const char *pszFrom)
166{
167 *ppsz = pszTo;
168 size_t cchCopy = strlen(pszFrom) + 1;
169 memcpy(pszTo, pszFrom, cchCopy);
170
171 return pszTo + cchCopy;
172}
173
174
175/**
176 * Converts the type enum to the size of the the event item data in bytes.
177 *
178 * @returns Event item data size in bytes.
179 * @param pEvtItemDesc The event item descriptor.
180 */
181static size_t rtTraceLogWrGetEvtItemDataSz(PCRTTRACELOGEVTITEMDESC pEvtItemDesc)
182{
183 size_t cb = 0;
184
185 switch (pEvtItemDesc->enmType)
186 {
187 case RTTRACELOGTYPE_BOOL:
188 case RTTRACELOGTYPE_UINT8:
189 case RTTRACELOGTYPE_INT8:
190 {
191 cb = 1;
192 break;
193 }
194 case RTTRACELOGTYPE_UINT16:
195 case RTTRACELOGTYPE_INT16:
196 {
197 cb = 2;
198 break;
199 }
200 case RTTRACELOGTYPE_UINT32:
201 case RTTRACELOGTYPE_INT32:
202 case RTTRACELOGTYPE_FLOAT32:
203 {
204 cb = 4;
205 break;
206 }
207 case RTTRACELOGTYPE_UINT64:
208 case RTTRACELOGTYPE_INT64:
209 case RTTRACELOGTYPE_FLOAT64:
210 {
211 cb = 8;
212 break;
213 }
214 case RTTRACELOGTYPE_RAWDATA:
215 {
216 cb = pEvtItemDesc->cbRawData;
217 break;
218 }
219 case RTTRACELOGTYPE_POINTER:
220 {
221 cb = sizeof(uintptr_t);
222 break;
223 }
224 case RTTRACELOGTYPE_SIZE:
225 {
226 cb = sizeof(size_t);
227 break;
228 }
229 default:
230 AssertMsgFailed(("Invalid type %d\n", pEvtItemDesc->enmType));
231 }
232
233 return cb;
234}
235
236
237/**
238 * Converts API severity enum to the stream representation.
239 *
240 * @returns Stream representation of the severity.
241 * @param enmSeverity The API severity.
242 */
243static uint32_t rtTraceLogWrConvSeverityToStream(RTTRACELOGEVTSEVERITY enmSeverity)
244{
245 switch (enmSeverity)
246 {
247 case RTTRACELOGEVTSEVERITY_INFO:
248 return TRACELOG_EVTDESC_SEVERITY_INFO;
249 case RTTRACELOGEVTSEVERITY_WARNING:
250 return TRACELOG_EVTDESC_SEVERITY_WARNING;
251 case RTTRACELOGEVTSEVERITY_ERROR:
252 return TRACELOG_EVTDESC_SEVERITY_ERROR;
253 case RTTRACELOGEVTSEVERITY_FATAL:
254 return TRACELOG_EVTDESC_SEVERITY_FATAL;
255 case RTTRACELOGEVTSEVERITY_DEBUG:
256 return TRACELOG_EVTDESC_SEVERITY_DEBUG;
257 default:
258 AssertMsgFailed(("Invalid severity %d\n", enmSeverity));
259 }
260
261 /* Should not happen. */
262 return TRACELOG_EVTDESC_SEVERITY_FATAL;
263}
264
265
266/**
267 * Converts API type enum to the stream representation.
268 *
269 * @returns Stream representation of the type.
270 * @param enmType The API type.
271 */
272static uint32_t rtTraceLogWrConvTypeToStream(RTTRACELOGTYPE enmType)
273{
274 switch (enmType)
275 {
276 case RTTRACELOGTYPE_BOOL:
277 return TRACELOG_EVTITEMDESC_TYPE_BOOL;
278 case RTTRACELOGTYPE_UINT8:
279 return TRACELOG_EVTITEMDESC_TYPE_UINT8;
280 case RTTRACELOGTYPE_INT8:
281 return TRACELOG_EVTITEMDESC_TYPE_INT8;
282 case RTTRACELOGTYPE_UINT16:
283 return TRACELOG_EVTITEMDESC_TYPE_UINT16;
284 case RTTRACELOGTYPE_INT16:
285 return TRACELOG_EVTITEMDESC_TYPE_INT16;
286 case RTTRACELOGTYPE_UINT32:
287 return TRACELOG_EVTITEMDESC_TYPE_UINT32;
288 case RTTRACELOGTYPE_INT32:
289 return TRACELOG_EVTITEMDESC_TYPE_INT32;
290 case RTTRACELOGTYPE_UINT64:
291 return TRACELOG_EVTITEMDESC_TYPE_UINT64;
292 case RTTRACELOGTYPE_INT64:
293 return TRACELOG_EVTITEMDESC_TYPE_INT64;
294 case RTTRACELOGTYPE_FLOAT32:
295 return TRACELOG_EVTITEMDESC_TYPE_FLOAT32;
296 case RTTRACELOGTYPE_FLOAT64:
297 return TRACELOG_EVTITEMDESC_TYPE_FLOAT64;
298 case RTTRACELOGTYPE_RAWDATA:
299 return TRACELOG_EVTITEMDESC_TYPE_RAWDATA;
300 case RTTRACELOGTYPE_POINTER:
301 return TRACELOG_EVTITEMDESC_TYPE_POINTER;
302 case RTTRACELOGTYPE_SIZE:
303 return TRACELOG_EVTITEMDESC_TYPE_SIZE;
304 default:
305 AssertMsgFailed(("Invalid type %d\n", enmType));
306 }
307
308 /* Should not happen. */
309 return RTTRACELOGTYPE_RAWDATA;
310}
311
312
313/**
314 * Initializes the internal representation of the event descriptor from the given one.
315 *
316 * @returns Pointer to the internal instance of the event descriptor.
317 * NULL if out of memory.
318 * @param pEvtDesc Pointer to the external descriptor.
319 */
320static PRTTRACELOGWREVTDESC rtTraceLogWrEvtDescInit(PCRTTRACELOGEVTDESC pEvtDesc)
321{
322 size_t cbAlloc = rtTraceLogWrtEvtDescGetSz(pEvtDesc);
323 size_t cbEvtData = 0;
324 PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTMemAllocZ(cbAlloc);
325 if (RT_LIKELY(pEvtDescInt))
326 {
327 char *pszStrSpace = (char *)&pEvtDescInt->aEvtItemDesc[pEvtDesc->cEvtItems]; /* Get space for strings after the descriptor. */
328
329 pEvtDescInt->EvtDesc.enmSeverity = pEvtDesc->enmSeverity;
330 pEvtDescInt->EvtDesc.cEvtItems = pEvtDesc->cEvtItems;
331 pEvtDescInt->EvtDesc.paEvtItemDesc = &pEvtDescInt->aEvtItemDesc[0];
332
333 /* Copy ID and optional description over. */
334 pszStrSpace = rtTraceLogWrCopyStr(&pEvtDescInt->EvtDesc.pszId, pszStrSpace, pEvtDesc->pszId);
335 if (pEvtDesc->pszDesc)
336 pszStrSpace = rtTraceLogWrCopyStr(&pEvtDescInt->EvtDesc.pszDesc, pszStrSpace, pEvtDesc->pszDesc);
337
338 /* Go through the event item descriptors and initialize them too. */
339 for (unsigned i = 0; i < pEvtDesc->cEvtItems; i++)
340 {
341 PCRTTRACELOGEVTITEMDESC pEvtItemDescFrom = &pEvtDesc->paEvtItemDesc[i];
342 PRTTRACELOGEVTITEMDESC pEvtItemDescTo = &pEvtDescInt->aEvtItemDesc[i];
343
344 pEvtItemDescTo->enmType = pEvtItemDescFrom->enmType;
345 pEvtItemDescTo->cbRawData = pEvtItemDescFrom->cbRawData;
346
347 cbEvtData += rtTraceLogWrGetEvtItemDataSz(pEvtItemDescFrom);
348 if ( pEvtItemDescTo->enmType == RTTRACELOGTYPE_RAWDATA
349 && !pEvtItemDescFrom->cbRawData)
350 pEvtDescInt->cRawDataNonStatic++;
351
352 pszStrSpace = rtTraceLogWrCopyStr(&pEvtItemDescTo->pszName, pszStrSpace, pEvtItemDescFrom->pszName);
353 if (pEvtItemDescFrom->pszDesc)
354 pszStrSpace = rtTraceLogWrCopyStr(&pEvtItemDescTo->pszDesc, pszStrSpace, pEvtItemDescFrom->pszDesc);
355 }
356
357 pEvtDescInt->cbEvtData = cbEvtData;
358 if (cbEvtData)
359 {
360 pEvtDescInt->pbEvt = (uint8_t *)RTMemAllocZ(cbEvtData);
361 if (!pEvtDescInt->pbEvt)
362 {
363 RTMemFree(pEvtDescInt);
364 pEvtDescInt = NULL;
365 }
366 }
367 }
368
369 return pEvtDescInt;
370}
371
372
373/**
374 * Wrapper around the stream callback.
375 *
376 * @returns IPRT status code returned by the stream callback.
377 * @param pThis The trace log writer instance.
378 * @param pvBuf The data to stream.
379 * @param cbBuf Number of bytes to stream.
380 */
381DECLINLINE(int) rtTraceLogWrStream(PRTTRACELOGWRINT pThis, const void *pvBuf, size_t cbBuf)
382{
383 return pThis->pfnStreamOut(pThis->pvUser, pvBuf, cbBuf, NULL);
384}
385
386
387/**
388 * Initializes a given event structure.
389 *
390 * @returns Total number of bytes for the event data associated with this event.
391 * @param pEvt Pointer to the event structure to initialise.
392 * @param pEvtDescInt The internal event descriptor to format the data accordingly to.
393 * @param fFlags Flags to use for this event.
394 * @param uGrpId The group ID to identify grouped events.
395 * @param uParentGrpId The parent group ID.
396 * @param pacbRawData Array of raw data size indicators.
397 */
398DECLINLINE(size_t) rtTraceLogWrEvtInit(PTRACELOGEVT pEvt,
399 PRTTRACELOGWREVTDESC pEvtDescInt, uint32_t fFlags,
400 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId,
401 size_t *pacbRawData)
402{
403 uint32_t cbEvtData = (uint32_t)pEvtDescInt->cbEvtData;
404 for (unsigned i = 0; i < pEvtDescInt->cRawDataNonStatic; i++)
405 cbEvtData += (uint32_t)pacbRawData[i];
406
407 uint32_t fEvtFlags = 0;
408 if (fFlags & RTTRACELOG_WR_ADD_EVT_F_GRP_START)
409 fEvtFlags |= TRACELOG_EVT_F_GRP_START;
410 if (fFlags & RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH)
411 fEvtFlags |= TRACELOG_EVT_F_GRP_END;
412
413 memcpy(&pEvt->szMagic[0], TRACELOG_EVT_MAGIC, sizeof(pEvt->szMagic));
414 pEvt->u64Ts = RTTimeNanoTS();
415 pEvt->u64EvtGrpId = uGrpId;
416 pEvt->u64EvtParentGrpId = uParentGrpId;
417 pEvt->fFlags = fEvtFlags;
418 pEvt->u32EvtDescId = pEvtDescInt->u32Id;
419 pEvt->cbEvtData = cbEvtData;
420 pEvt->cRawEvtDataSz = pEvtDescInt->cRawDataNonStatic;
421
422 return cbEvtData;
423}
424
425
426/**
427 * Streams the whole event including associated data.
428 *
429 * @returns IPRT status code.
430 * @param pThis The trace log writer instance.
431 * @param pEvt Pointer to the initialised event structure.
432 * @param pvEvtData The raw event data.
433 * @param cbEvtData Size of the event data.
434 * @param pacbRawData Pointer to the array of size indicators for non static
435 * raw data in the event data stream.
436 */
437DECLINLINE(int) rtTraceLogWrEvtStream(PRTTRACELOGWRINT pThis, PTRACELOGEVT pEvt, const void *pvEvtData,
438 size_t cbEvtData, size_t *pacbRawData)
439{
440 /** @todo Get rid of locking. */
441 int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT);
442 if (RT_SUCCESS(rc))
443 {
444 pEvt->u64SeqNo = ASMAtomicIncU64(&pThis->u64SeqNoNext);
445
446 /* Write the data out. */
447 rc = rtTraceLogWrStream(pThis, pEvt, sizeof(TRACELOGEVT));
448 if ( RT_SUCCESS(rc)
449 && pEvt->cRawEvtDataSz)
450 rc = rtTraceLogWrStream(pThis, pacbRawData, pEvt->cRawEvtDataSz * sizeof(size_t));
451 if ( RT_SUCCESS(rc)
452 && cbEvtData)
453 rc = rtTraceLogWrStream(pThis, pvEvtData, cbEvtData);
454 RTSemMutexRelease(pThis->hMtx);
455 }
456
457 return rc;
458}
459
460
461/**
462 * Returns the intenral event descriptor for the given event descriptor.
463 *
464 * @returns Pointer to the internal event descriptor or NULL if not found.
465 * @param pThis The trace log writer instance.
466 * @param pEvtDesc The event descriptor to search for.
467 */
468DECLINLINE(PRTTRACELOGWREVTDESC) rtTraceLogWrEvtDescGetInternal(PRTTRACELOGWRINT pThis,
469 PCRTTRACELOGEVTDESC pEvtDesc)
470{
471 int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT);
472 if (RT_SUCCESS(rc))
473 {
474 PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTAvlPVGet(&pThis->pTreeEvtDescs, (void *)pEvtDesc);
475 RTSemMutexRelease(pThis->hMtx);
476 return pEvtDescInt;
477 }
478
479 return NULL;
480}
481
482
483/**
484 * Initializes the trace log.
485 *
486 * @returns IPRT status code.
487 * @param pThis The trace log writer instance.
488 * @param pszDesc The description to use.
489 */
490static int rtTraceLogWrInit(PRTTRACELOGWRINT pThis, const char *pszDesc)
491{
492 /* Start by assembling the header. */
493 TRACELOGHDR Hdr;
494
495 RT_ZERO(Hdr);
496 memcpy(&Hdr.szMagic[0], TRACELOG_HDR_MAGIC, sizeof(Hdr.szMagic));
497 Hdr.u32Endianess = TRACELOG_HDR_ENDIANESS; /* Endianess marker. */
498 Hdr.u32Version = TRACELOG_VERSION;
499 Hdr.fFlags = 0;
500 Hdr.cbStrDesc = pszDesc ? (uint32_t)strlen(pszDesc) : 0;
501 Hdr.cbTypePtr = sizeof(uintptr_t);
502 Hdr.cbTypeSize = sizeof(size_t);
503 Hdr.u64TsStart = RTTimeNanoTS();
504 int rc = rtTraceLogWrStream(pThis, &Hdr, sizeof(Hdr));
505 if ( RT_SUCCESS(rc)
506 && pThis->pszDesc)
507 rc = rtTraceLogWrStream(pThis, pszDesc, Hdr.cbStrDesc);
508
509 return rc;
510}
511
512
513static DECLCALLBACK(int) rtTraceLogWrCheckForOverlappingIds(PAVLPVNODECORE pCore, void *pvParam)
514{
515 PCRTTRACELOGEVTDESC pEvtDesc = (PCRTTRACELOGEVTDESC)pvParam;
516 PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)pCore;
517
518 if (!RTStrCmp(pEvtDesc->pszId, pEvtDescInt->EvtDesc.pszId))
519 return VERR_ALREADY_EXISTS;
520
521 return VINF_SUCCESS;
522}
523
524
525static DECLCALLBACK(int) rtTraceLogWrEvtDescsDestroy(PAVLPVNODECORE pCore, void *pvParam)
526{
527 PRTTRACELOGWREVTDESC pEvtDesc = (PRTTRACELOGWREVTDESC)pCore;
528 RT_NOREF(pvParam);
529
530 RTMemFree(pEvtDesc->pbEvt);
531 RTMemFree(pEvtDesc);
532 return VINF_SUCCESS;
533}
534
535
536/**
537 * Adds a new event descriptor to the trace log.
538 *
539 * @returns IPRT status code.
540 * @param pThis The trace log writer instance.
541 * @param pEvtDesc The event descriptor to add.
542 * @param ppEvtDescInt Where to store the pointer to the internal
543 * event descriptor - optional.
544 */
545static int rtTraceLogWrEvtDescAdd(PRTTRACELOGWRINT pThis, PCRTTRACELOGEVTDESC pEvtDesc,
546 PRTTRACELOGWREVTDESC *ppEvtDescInt)
547{
548 int rc = RTSemMutexRequest(pThis->hMtx, RT_INDEFINITE_WAIT);
549 if (RT_SUCCESS(rc))
550 {
551 PRTTRACELOGWREVTDESC pEvtDescInt = (PRTTRACELOGWREVTDESC)RTAvlPVGet(&pThis->pTreeEvtDescs, (void *)pEvtDesc);
552 if (!pEvtDescInt)
553 {
554 rc = RTAvlPVDoWithAll(&pThis->pTreeEvtDescs, true, rtTraceLogWrCheckForOverlappingIds, (void *)pEvtDesc);
555 if (RT_SUCCESS(rc))
556 {
557 pEvtDescInt = rtTraceLogWrEvtDescInit(pEvtDesc);
558 if (RT_LIKELY(pEvtDescInt))
559 {
560 pEvtDescInt->Core.Key = (void *)pEvtDesc;
561 pEvtDescInt->u32Id = pThis->cEvtDescs++;
562 bool fIns = RTAvlPVInsert(&pThis->pTreeEvtDescs, &pEvtDescInt->Core);
563 Assert(fIns); RT_NOREF(fIns);
564 }
565 else
566 rc = VERR_NO_MEMORY;
567
568 if (RT_SUCCESS(rc))
569 {
570 TRACELOGEVTDESC EvtDesc;
571
572 RT_ZERO(EvtDesc);
573 memcpy(&EvtDesc.szMagic[0], TRACELOG_EVTDESC_MAGIC, sizeof(EvtDesc.szMagic));
574 EvtDesc.u32Id = pEvtDescInt->u32Id;
575 EvtDesc.u32Severity = rtTraceLogWrConvSeverityToStream(pEvtDescInt->EvtDesc.enmSeverity);
576 EvtDesc.cbStrId = (uint32_t)strlen(pEvtDescInt->EvtDesc.pszId);
577 EvtDesc.cbStrDesc = pEvtDescInt->EvtDesc.pszDesc ? (uint32_t)strlen(pEvtDescInt->EvtDesc.pszDesc) : 0;
578 EvtDesc.cEvtItems = pEvtDescInt->EvtDesc.cEvtItems;
579 rc = rtTraceLogWrStream(pThis, &EvtDesc, sizeof(EvtDesc));
580 if (RT_SUCCESS(rc))
581 rc = rtTraceLogWrStream(pThis, pEvtDescInt->EvtDesc.pszId, EvtDesc.cbStrId);
582 if ( RT_SUCCESS(rc)
583 && pEvtDescInt->EvtDesc.pszDesc)
584 rc = rtTraceLogWrStream(pThis, pEvtDescInt->EvtDesc.pszDesc, EvtDesc.cbStrDesc);
585 if (RT_SUCCESS(rc))
586 {
587 /* Go through the event items. */
588 for (unsigned idxEvtItem = 0; idxEvtItem < EvtDesc.cEvtItems && RT_SUCCESS(rc); idxEvtItem++)
589 {
590 PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDescInt->EvtDesc.paEvtItemDesc[idxEvtItem];
591 TRACELOGEVTITEMDESC EvtItemDesc;
592
593 RT_ZERO(EvtItemDesc);
594 memcpy(&EvtItemDesc.szMagic[0], TRACELOG_EVTITEMDESC_MAGIC, sizeof(EvtItemDesc.szMagic));
595 EvtItemDesc.cbStrName = (uint32_t)strlen(pEvtItemDesc->pszName);
596 EvtItemDesc.cbStrDesc = pEvtItemDesc->pszDesc ? (uint32_t)strlen(pEvtItemDesc->pszDesc) : 0;
597 EvtItemDesc.u32Type = rtTraceLogWrConvTypeToStream(pEvtItemDesc->enmType);
598 EvtItemDesc.cbRawData = (uint32_t)pEvtItemDesc->cbRawData;
599 rc = rtTraceLogWrStream(pThis, &EvtItemDesc, sizeof(EvtItemDesc));
600 if (RT_SUCCESS(rc))
601 rc = rtTraceLogWrStream(pThis, pEvtItemDesc->pszName, EvtItemDesc.cbStrName);
602 if ( RT_SUCCESS(rc)
603 && pEvtItemDesc->pszDesc)
604 rc = rtTraceLogWrStream(pThis, pEvtItemDesc->pszDesc, EvtItemDesc.cbStrDesc);
605 }
606 }
607 }
608 }
609
610 if ( RT_SUCCESS(rc)
611 && ppEvtDescInt)
612 *ppEvtDescInt = pEvtDescInt;
613 }
614 else
615 rc = VERR_ALREADY_EXISTS;
616 RTSemMutexRelease(pThis->hMtx);
617 }
618
619 return rc;
620}
621
622
623/**
624 * Fills a given buffer with the given event data as described in the given descriptor.
625 *
626 * @returns IPRT status code.
627 * @param pThis The trace log writer instance.
628 * @param pEvtDescInt Pointer to the internal event descriptor.
629 * @param pb The byte buffer to fill.
630 * @param va The event data.
631 */
632static int rtTraceLogWrEvtFill(PRTTRACELOGWRINT pThis, PRTTRACELOGWREVTDESC pEvtDescInt, uint8_t *pb, va_list va)
633{
634 int rc = VINF_SUCCESS;
635 uint8_t *pbCur = pb;
636
637 RT_NOREF(pThis);
638
639 for (unsigned i = 0; i < pEvtDescInt->EvtDesc.cEvtItems; i++)
640 {
641 PCRTTRACELOGEVTITEMDESC pEvtItemDesc = &pEvtDescInt->EvtDesc.paEvtItemDesc[i];
642
643 size_t cbItem = rtTraceLogWrGetEvtItemDataSz(pEvtItemDesc);
644 switch (cbItem)
645 {
646 case sizeof(uint8_t):
647 *pbCur++ = va_arg(va, /*uint8_t*/ unsigned);
648 break;
649 case sizeof(uint16_t):
650 *(uint16_t *)pbCur = va_arg(va, /*uint16_t*/ unsigned);
651 pbCur += sizeof(uint16_t);
652 break;
653 case sizeof(uint32_t):
654 *(uint32_t *)pbCur = va_arg(va, uint32_t);
655 pbCur += sizeof(uint32_t);
656 break;
657 case sizeof(uint64_t):
658 *(uint64_t *)pbCur = va_arg(va, uint64_t);
659 pbCur += sizeof(uint64_t);
660 break;
661 default:
662 /* Some raw data item. */
663 Assert(pEvtItemDesc->enmType == RTTRACELOGTYPE_RAWDATA);
664 if (cbItem != 0)
665 {
666 /* Static raw data. */
667 void *pvSrc = va_arg(va, void *);
668 memcpy(pbCur, pvSrc, cbItem);
669 pbCur += cbItem;
670 }
671 else
672 {
673 AssertMsgFailed(("Not implemented!\n"));
674 rc = VERR_NOT_IMPLEMENTED;
675 }
676 }
677 }
678
679 return rc;
680}
681
682
683/**
684 * @copydoc FNRTTRACELOGWRSTREAM
685 */
686static DECLCALLBACK(int) rtTraceLogWrFileStream(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
687{
688 RTFILE hFile = (RTFILE)pvUser;
689 return RTFileWrite(hFile, pvBuf, cbBuf, pcbWritten);
690}
691
692
693/**
694 * @copydoc FNRTTRACELOGSTREAMCLOSE
695 */
696static DECLCALLBACK(int) rtTraceLogWrFileStreamClose(void *pvUser)
697{
698 RTFILE hFile = (RTFILE)pvUser;
699 return RTFileClose(hFile);
700}
701
702
703RTDECL(int) RTTraceLogWrCreate(PRTTRACELOGWR phTraceLogWr, const char *pszDesc,
704 PFNRTTRACELOGWRSTREAM pfnStreamOut,
705 PFNRTTRACELOGSTREAMCLOSE pfnStreamClose, void *pvUser)
706{
707 AssertPtrReturn(phTraceLogWr, VERR_INVALID_POINTER);
708 AssertPtrReturn(pfnStreamOut, VERR_INVALID_POINTER);
709 AssertPtrReturn(pfnStreamClose, VERR_INVALID_POINTER);
710 int rc = VINF_SUCCESS;
711 PRTTRACELOGWRINT pThis = (PRTTRACELOGWRINT)RTMemAllocZ(sizeof(*pThis));
712 if (pThis)
713 {
714 rc = RTSemMutexCreate(&pThis->hMtx);
715 if (RT_SUCCESS(rc))
716 {
717 pThis->u32Magic = RTTRACELOGWR_MAGIC;
718 pThis->pfnStreamOut = pfnStreamOut;
719 pThis->pfnStreamClose = pfnStreamClose;
720 pThis->pvUser = pvUser;
721 pThis->u64SeqNoNext = 0;
722 pThis->pTreeEvtDescs = NULL;
723 pThis->cEvtDescs = 0;
724 rc = rtTraceLogWrInit(pThis, pszDesc);
725 if (RT_SUCCESS(rc))
726 {
727 *phTraceLogWr = pThis;
728 return VINF_SUCCESS;
729 }
730 }
731 RTMemFree(pThis);
732 }
733 else
734 rc = VERR_NO_MEMORY;
735
736 return rc;
737}
738
739
740RTDECL(int) RTTraceLogWrCreateFile(PRTTRACELOGWR phTraceLogWr, const char *pszDesc,
741 const char *pszFilename)
742{
743 AssertPtrReturn(phTraceLogWr, VERR_INVALID_POINTER);
744 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
745
746 RTFILE hFile = NIL_RTFILE;
747 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
748 if (RT_SUCCESS(rc))
749 {
750 rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrFileStream,
751 rtTraceLogWrFileStreamClose, hFile);
752 if (RT_FAILURE(rc))
753 {
754 RTFileClose(hFile);
755 RTFileDelete(pszFilename);
756 }
757 }
758
759 return rc;
760}
761
762
763/**
764 * @copydoc FNRTTRACELOGWRSTREAM
765 */
766static DECLCALLBACK(int) rtTraceLogWrTcpStream(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
767{
768 PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)pvUser;
769 int rc = RTTcpWrite(pTraceLogTcp->hSock, pvBuf, cbBuf);
770 if ( RT_SUCCESS(rc)
771 && pcbWritten)
772 *pcbWritten = cbBuf;
773
774 return rc;
775}
776
777
778/**
779 * @copydoc FNRTTRACELOGSTREAMCLOSE
780 */
781static DECLCALLBACK(int) rtTraceLogWrTcpStreamClose(void *pvUser)
782{
783 PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)pvUser;
784 if (pTraceLogTcp->fIsServer)
785 {
786 RTTcpServerDisconnectClient2(pTraceLogTcp->hSock);
787 RTTcpServerDestroy(pTraceLogTcp->pTcpSrv);
788 }
789 else
790 RTTcpClientClose(pTraceLogTcp->hSock);
791
792 RTMemFree(pTraceLogTcp);
793 return VINF_SUCCESS;
794}
795
796
797RTDECL(int) RTTraceLogWrCreateTcpServer(PRTTRACELOGWR phTraceLogWr, const char *pszDesc,
798 const char *pszListen, unsigned uPort)
799{
800 int rc = VINF_SUCCESS;
801 PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)RTMemAllocZ(sizeof(*pTraceLogTcp));
802 if (RT_LIKELY(pTraceLogTcp))
803 {
804 pTraceLogTcp->fIsServer = true;
805
806 rc = RTTcpServerCreateEx(pszListen, uPort, &pTraceLogTcp->pTcpSrv);
807 if (RT_SUCCESS(rc))
808 {
809 rc = RTTcpServerListen2(pTraceLogTcp->pTcpSrv, &pTraceLogTcp->hSock);
810 if (RT_SUCCESS(rc))
811 {
812 rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrTcpStream,
813 rtTraceLogWrTcpStreamClose, pTraceLogTcp);
814 if (RT_SUCCESS(rc))
815 return VINF_SUCCESS;
816
817 RTTcpServerDisconnectClient2(pTraceLogTcp->hSock);
818 }
819
820 RTTcpServerDestroy(pTraceLogTcp->pTcpSrv);
821 }
822
823 RTMemFree(pTraceLogTcp);
824 }
825 else
826 rc = VERR_NO_MEMORY;
827
828 return rc;
829}
830
831
832RTDECL(int) RTTraceLogWrCreateTcpClient(PRTTRACELOGWR phTraceLogWr, const char *pszDesc,
833 const char *pszAddress, unsigned uPort)
834{
835 int rc = VINF_SUCCESS;
836 PRTTRACELOGWRTCP pTraceLogTcp = (PRTTRACELOGWRTCP)RTMemAllocZ(sizeof(*pTraceLogTcp));
837 if (RT_LIKELY(pTraceLogTcp))
838 {
839 pTraceLogTcp->fIsServer = false;
840
841 rc = RTTcpClientConnect(pszAddress, uPort, &pTraceLogTcp->hSock);
842 if (RT_SUCCESS(rc))
843 {
844 rc = RTTraceLogWrCreate(phTraceLogWr, pszDesc, rtTraceLogWrTcpStream,
845 rtTraceLogWrTcpStreamClose, pTraceLogTcp);
846 if (RT_SUCCESS(rc))
847 return VINF_SUCCESS;
848
849 RTTcpClientClose(pTraceLogTcp->hSock);
850 }
851
852 RTMemFree(pTraceLogTcp);
853 }
854 else
855 rc = VERR_NO_MEMORY;
856
857 return rc;
858}
859
860
861RTDECL(int) RTTraceLogWrDestroy(RTTRACELOGWR hTraceLogWr)
862{
863 PRTTRACELOGWRINT pThis = hTraceLogWr;
864 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
865
866 pThis->u32Magic = RTTRACELOGWR_MAGIC_DEAD;
867 pThis->pfnStreamClose(pThis->pvUser);
868 RTAvlPVDestroy(&pThis->pTreeEvtDescs, rtTraceLogWrEvtDescsDestroy, NULL);
869 RTSemMutexDestroy(pThis->hMtx);
870 RTMemFree(pThis);
871 return VINF_SUCCESS;
872}
873
874
875RTDECL(int) RTTraceLogWrAddEvtDesc(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc)
876{
877 PRTTRACELOGWRINT pThis = hTraceLogWr;
878 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
879 AssertPtrReturn(pEvtDesc, VERR_INVALID_POINTER);
880
881 return rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, NULL);
882}
883
884
885RTDECL(int) RTTraceLogWrEvtAdd(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags,
886 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId,
887 const void *pvEvtData, size_t *pacbRawData)
888{
889 PRTTRACELOGWRINT pThis = hTraceLogWr;
890 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
891
892 int rc = VINF_SUCCESS;
893 PRTTRACELOGWREVTDESC pEvtDescInt = rtTraceLogWrEvtDescGetInternal(pThis, pEvtDesc);
894 if (RT_UNLIKELY(!pEvtDescInt))
895 rc = rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, &pEvtDescInt);
896
897 if ( RT_SUCCESS(rc)
898 && VALID_PTR(pEvtDescInt))
899 {
900 TRACELOGEVT Evt;
901 size_t cbEvtData = rtTraceLogWrEvtInit(&Evt, pEvtDescInt, fFlags, uGrpId, uParentGrpId, pacbRawData);
902
903 rc = rtTraceLogWrEvtStream(pThis, &Evt, pvEvtData, cbEvtData, pacbRawData);
904 }
905
906 return rc;
907}
908
909
910RTDECL(int) RTTraceLogWrEvtAddSg(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags,
911 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId,
912 PRTSGBUF *pSgBufEvtData, size_t *pacbRawData)
913{
914 RT_NOREF(hTraceLogWr, pEvtDesc, fFlags, uGrpId, uParentGrpId, pSgBufEvtData, pacbRawData);
915 return VERR_NOT_IMPLEMENTED;
916}
917
918
919RTDECL(int) RTTraceLogWrEvtAddLV(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags,
920 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, va_list va)
921{
922 PRTTRACELOGWRINT pThis = hTraceLogWr;
923 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
924
925 int rc = VINF_SUCCESS;
926 PRTTRACELOGWREVTDESC pEvtDescInt = rtTraceLogWrEvtDescGetInternal(pThis, pEvtDesc);
927 if (RT_UNLIKELY(!pEvtDescInt))
928 rc = rtTraceLogWrEvtDescAdd(pThis, pEvtDesc, &pEvtDescInt);
929
930 if ( RT_SUCCESS(rc)
931 && VALID_PTR(pEvtDescInt))
932 {
933 TRACELOGEVT Evt;
934 size_t cbEvtData = rtTraceLogWrEvtInit(&Evt, pEvtDescInt, fFlags, uGrpId, uParentGrpId, NULL);
935
936 if (cbEvtData)
937 rc = rtTraceLogWrEvtFill(pThis, pEvtDescInt, pEvtDescInt->pbEvt, va);
938 if (RT_SUCCESS(rc))
939 rc = rtTraceLogWrEvtStream(pThis, &Evt, pEvtDescInt->pbEvt, cbEvtData, NULL);
940 }
941
942 return rc;
943}
944
945
946RTDECL(int) RTTraceLogWrEvtAddL(RTTRACELOGWR hTraceLogWr, PCRTTRACELOGEVTDESC pEvtDesc, uint32_t fFlags,
947 RTTRACELOGEVTGRPID uGrpId, RTTRACELOGEVTGRPID uParentGrpId, ...)
948{
949 va_list va;
950 va_start(va, uParentGrpId);
951 int rc = RTTraceLogWrEvtAddLV(hTraceLogWr, pEvtDesc, fFlags, uGrpId, uParentGrpId, va);
952 va_end(va);
953 return rc;
954}
955
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette