bumping version to 3.5-rc1
[supercollider.git] / server / supernova / utilities / asynchronous_log.hpp
blob2dfca31e6671631b0098c1999f9d4f5d8ec5f5f0
1 // class for asynchronous logging
2 // Copyright (C) 2011 Tim Blechmann
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
19 #ifndef UTILITIES_ASYNCHRONOUS_LOG_HPP
20 #define UTILITIES_ASYNCHRONOUS_LOG_HPP
22 #include <cstring>
23 #include <cstdio>
24 #include <cstdarg>
26 #include <boost/bind.hpp>
27 #include <boost/thread.hpp>
28 #include <boost/lockfree/ringbuffer.hpp>
29 #include <boost/mpl/if.hpp>
31 #include <nova-tt/semaphore.hpp>
33 namespace nova {
34 namespace asynchronous_log_impl {
36 using namespace boost;
38 struct asynchronous_log:
39 noncopyable
41 bool log_printf(const char *fmt, ...)
43 va_list vargs;
44 va_start(vargs, fmt);
46 bool result = log_printf(fmt, vargs);
47 va_end(vargs);
48 return result;
51 bool log_printf(const char *fmt, va_list vargs)
53 array<char, 4096> scratchpad;
54 int print_result = vsnprintf(scratchpad.c_array(), scratchpad.size(), fmt, vargs);
56 if (print_result >= scratchpad.size())
57 fprintf(stderr, "warning: log message truncated");
59 return log(scratchpad.c_array(), print_result);
62 bool log(const char * string)
64 size_t length = strlen(string);
65 return log(string, length);
68 bool log(const char * string, size_t length)
70 size_t total_enqueued = buffer.enqueue(string, length);
71 if (total_enqueued == 0)
72 return false;
74 sem.post();
76 if (total_enqueued == length)
77 return true;
79 string += total_enqueued;
80 length -= total_enqueued;
82 for (;;) {
83 size_t enqueued = buffer.enqueue(string, length);
84 if (enqueued == 0)
85 continue;
87 sem.post();
89 if (enqueued == length)
90 break;
92 string += total_enqueued;
93 length -= total_enqueued;
96 return true;
99 size_t read_log(char * out_buffer, size_t size)
101 if (sem.try_wait())
102 return read(out_buffer, size);
103 else
104 return 0;
107 size_t read_log_waiting(char * out_buffer, size_t size)
109 sem.wait();
110 return read(out_buffer, size);
113 size_t read(char * out_buffer, size_t size)
115 return buffer.dequeue(out_buffer, size);
118 void interrrupt(void)
120 sem.post();
123 private:
124 lockfree::ringbuffer<char, 32768> buffer;
125 nova::semaphore sem;
128 struct asynchronous_log_thread:
129 asynchronous_log
131 public:
132 asynchronous_log_thread(void):
133 running_flag(true), thread_(bind(&asynchronous_log_thread::run, this))
136 ~asynchronous_log_thread(void)
138 running_flag = false;
139 interrrupt();
140 thread_.join();
143 void run(void)
145 while (running_flag.load()) {
146 size_t read_chars = read_log_waiting(out_buffer.c_array(), out_buffer.size());
147 post_outbuffer(read_chars);
149 while (read_chars == out_buffer.size()) {
150 read_chars = read(out_buffer.c_array(), out_buffer.size());
151 post_outbuffer(read_chars);
154 size_t read_chars = read_log(out_buffer.c_array(), out_buffer.size());
155 post_outbuffer(read_chars);
158 void post_outbuffer(size_t read_chars)
160 for (size_t i = 0; i != read_chars; ++i)
161 putchar(out_buffer[i]);
162 fflush(stdout);
165 private:
166 thread thread_;
167 atomic_bool running_flag;
168 array<char, 4096> out_buffer;
171 } /* namespace asynchronous_log_impl */
173 using asynchronous_log_impl::asynchronous_log;
174 using asynchronous_log_impl::asynchronous_log_thread;
176 } /* namespace nova */
178 #endif /* UTILITIES_ASYNCHRONOUS_LOG_HPP */