1 | #include "jemalloc/internal/jemalloc_preamble.h" |
2 | #include "jemalloc/internal/jemalloc_internal_includes.h" |
3 | |
4 | #include "jemalloc/internal/buf_writer.h" |
5 | #include "jemalloc/internal/malloc_io.h" |
6 | |
7 | static void * |
8 | buf_writer_allocate_internal_buf(tsdn_t *tsdn, size_t buf_len) { |
9 | #ifdef JEMALLOC_JET |
10 | if (buf_len > SC_LARGE_MAXCLASS) { |
11 | return NULL; |
12 | } |
13 | #else |
14 | assert(buf_len <= SC_LARGE_MAXCLASS); |
15 | #endif |
16 | return iallocztm(tsdn, buf_len, sz_size2index(buf_len), false, NULL, |
17 | true, arena_get(tsdn, 0, false), true); |
18 | } |
19 | |
20 | static void |
21 | buf_writer_free_internal_buf(tsdn_t *tsdn, void *buf) { |
22 | if (buf != NULL) { |
23 | idalloctm(tsdn, buf, NULL, NULL, true, true); |
24 | } |
25 | } |
26 | |
27 | static void |
28 | buf_writer_assert(buf_writer_t *buf_writer) { |
29 | assert(buf_writer != NULL); |
30 | assert(buf_writer->write_cb != NULL); |
31 | if (buf_writer->buf != NULL) { |
32 | assert(buf_writer->buf_size > 0); |
33 | } else { |
34 | assert(buf_writer->buf_size == 0); |
35 | assert(buf_writer->internal_buf); |
36 | } |
37 | assert(buf_writer->buf_end <= buf_writer->buf_size); |
38 | } |
39 | |
40 | bool |
41 | buf_writer_init(tsdn_t *tsdn, buf_writer_t *buf_writer, write_cb_t *write_cb, |
42 | void *cbopaque, char *buf, size_t buf_len) { |
43 | if (write_cb != NULL) { |
44 | buf_writer->write_cb = write_cb; |
45 | } else { |
46 | buf_writer->write_cb = je_malloc_message != NULL ? |
47 | je_malloc_message : wrtmessage; |
48 | } |
49 | buf_writer->cbopaque = cbopaque; |
50 | assert(buf_len >= 2); |
51 | if (buf != NULL) { |
52 | buf_writer->buf = buf; |
53 | buf_writer->internal_buf = false; |
54 | } else { |
55 | buf_writer->buf = buf_writer_allocate_internal_buf(tsdn, |
56 | buf_len); |
57 | buf_writer->internal_buf = true; |
58 | } |
59 | if (buf_writer->buf != NULL) { |
60 | buf_writer->buf_size = buf_len - 1; /* Allowing for '\0'. */ |
61 | } else { |
62 | buf_writer->buf_size = 0; |
63 | } |
64 | buf_writer->buf_end = 0; |
65 | buf_writer_assert(buf_writer); |
66 | return buf_writer->buf == NULL; |
67 | } |
68 | |
69 | void |
70 | buf_writer_flush(buf_writer_t *buf_writer) { |
71 | buf_writer_assert(buf_writer); |
72 | if (buf_writer->buf == NULL) { |
73 | return; |
74 | } |
75 | buf_writer->buf[buf_writer->buf_end] = '\0'; |
76 | buf_writer->write_cb(buf_writer->cbopaque, buf_writer->buf); |
77 | buf_writer->buf_end = 0; |
78 | buf_writer_assert(buf_writer); |
79 | } |
80 | |
81 | void |
82 | buf_writer_cb(void *buf_writer_arg, const char *s) { |
83 | buf_writer_t *buf_writer = (buf_writer_t *)buf_writer_arg; |
84 | buf_writer_assert(buf_writer); |
85 | if (buf_writer->buf == NULL) { |
86 | buf_writer->write_cb(buf_writer->cbopaque, s); |
87 | return; |
88 | } |
89 | size_t i, slen, n; |
90 | for (i = 0, slen = strlen(s); i < slen; i += n) { |
91 | if (buf_writer->buf_end == buf_writer->buf_size) { |
92 | buf_writer_flush(buf_writer); |
93 | } |
94 | size_t s_remain = slen - i; |
95 | size_t buf_remain = buf_writer->buf_size - buf_writer->buf_end; |
96 | n = s_remain < buf_remain ? s_remain : buf_remain; |
97 | memcpy(buf_writer->buf + buf_writer->buf_end, s + i, n); |
98 | buf_writer->buf_end += n; |
99 | buf_writer_assert(buf_writer); |
100 | } |
101 | assert(i == slen); |
102 | } |
103 | |
104 | void |
105 | buf_writer_terminate(tsdn_t *tsdn, buf_writer_t *buf_writer) { |
106 | buf_writer_assert(buf_writer); |
107 | buf_writer_flush(buf_writer); |
108 | if (buf_writer->internal_buf) { |
109 | buf_writer_free_internal_buf(tsdn, buf_writer->buf); |
110 | } |
111 | } |
112 | |
113 | void |
114 | buf_writer_pipe(buf_writer_t *buf_writer, read_cb_t *read_cb, |
115 | void *read_cbopaque) { |
116 | /* |
117 | * A tiny local buffer in case the buffered writer failed to allocate |
118 | * at init. |
119 | */ |
120 | static char backup_buf[16]; |
121 | static buf_writer_t backup_buf_writer; |
122 | |
123 | buf_writer_assert(buf_writer); |
124 | assert(read_cb != NULL); |
125 | if (buf_writer->buf == NULL) { |
126 | buf_writer_init(TSDN_NULL, &backup_buf_writer, |
127 | buf_writer->write_cb, buf_writer->cbopaque, backup_buf, |
128 | sizeof(backup_buf)); |
129 | buf_writer = &backup_buf_writer; |
130 | } |
131 | assert(buf_writer->buf != NULL); |
132 | ssize_t nread = 0; |
133 | do { |
134 | buf_writer->buf_end += nread; |
135 | buf_writer_assert(buf_writer); |
136 | if (buf_writer->buf_end == buf_writer->buf_size) { |
137 | buf_writer_flush(buf_writer); |
138 | } |
139 | nread = read_cb(read_cbopaque, |
140 | buf_writer->buf + buf_writer->buf_end, |
141 | buf_writer->buf_size - buf_writer->buf_end); |
142 | } while (nread > 0); |
143 | buf_writer_flush(buf_writer); |
144 | } |
145 | |