1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "private.h"
6 
7 #include <stdarg.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 
11 #include <zircon/syscalls.h>
12 #include <zircon/syscalls/log.h>
13 
14 #ifdef FDIO_LLDEBUG
15 #define LOGBUF_MAX (ZX_LOG_RECORD_MAX - sizeof(zx_log_record_t))
16 
fdio_lldebug_log_write(const void * _data,size_t len)17 static ssize_t fdio_lldebug_log_write(const void* _data, size_t len) {
18     static thread_local struct {
19         zx_handle_t log;
20         uint32_t next;
21         char data[LOGBUF_MAX];
22     }* logbuf = NULL;
23 
24     if (logbuf == NULL) {
25         if ((logbuf = calloc(1, sizeof(*logbuf))) == NULL) {
26             return len;
27         }
28         if (zx_debuglog_create(0, 0, &logbuf->log) != ZX_OK) {
29             free(logbuf);
30             logbuf = NULL;
31             return len;
32         }
33     }
34 
35     const char* data = _data;
36     size_t r = len;
37     while (len-- > 0) {
38         char c = *data++;
39         if (c == '\n') {
40             zx_log_write(logbuf->log, logbuf->next, logbuf->data, 0);
41             logbuf->next = 0;
42             continue;
43         }
44         if (c < ' ') {
45             continue;
46         }
47         logbuf->data[logbuf->next++] = c;
48         if (logbuf->next == LOGBUF_MAX) {
49             zx_log_write(logbuf->log, logbuf->next, logbuf->data, 0);
50             logbuf->next = 0;
51             continue;
52         }
53     }
54     return r;
55 }
56 
57 static unsigned debug_level = FDIO_LLDEBUG;
58 
fdio_lldebug_printf(unsigned level,const char * fmt,...)59 void fdio_lldebug_printf(unsigned level, const char* fmt, ...) {
60     if (debug_level >= level) {
61         va_list ap;
62         char buf[128];
63         va_start(ap, fmt);
64         size_t sz = vsnprintf(buf, sizeof(buf), fmt, ap);
65         va_end(ap);
66         fdio_lldebug_log_write(buf, sz > sizeof(buf) ? sizeof(buf) : sz);
67     }
68 }
69 #endif
70 
fdio_set_debug_level(unsigned level)71 void fdio_set_debug_level(unsigned level) {
72 #ifdef FDIO_LLDEBUG
73     debug_level = level;
74 #endif
75 }
76 
77 #ifdef FDIO_ALLOCDEBUG
78 
79 #define PSZ 128
80 
81 static char POOL[PSZ * 256];
82 static char* NEXT = POOL;
83 static mtx_t pool_lock;
84 
fdio_alloc(size_t n,size_t sz)85 void* fdio_alloc(size_t n, size_t sz) {
86     if ((n > 1) || (sz > PSZ)) {
87         return NULL;
88     }
89     void* ptr = NULL;
90     mtx_lock(&pool_lock);
91     if ((NEXT - POOL) < (int)sizeof(POOL)) {
92         ptr = NEXT;
93         NEXT += PSZ;
94     } else {
95         LOG(1, "fdio: OUT OF FDIO_T POOL SPACE\n");
96     }
97     mtx_unlock(&pool_lock);
98     LOG(5, "fdio: io: alloc: %p\n", ptr);
99     return ptr;
100 }
101 #endif
102 
fdio_free(fdio_t * io)103 void fdio_free(fdio_t* io) {
104     LOG(5, "fdio: io: free: %p\n", io);
105     io->magic = 0xDEAD0123;
106     io->ops = NULL;
107 #ifndef FDIO_ALLOCDEBUG
108     free(io);
109 #endif
110 }
111