class library: Volume - use ServerBoot to send synthdef
[supercollider.git] / server / supernova / utilities / asynchronous_log.hpp
blob399cc4f9a5ebb24f8863e9b0601fde8a5604aa5f
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 <thread>
27 #include <array>
28 #include <boost/lockfree/spsc_queue.hpp>
29 #include <boost/mpl/if.hpp>
31 #include <nova-tt/semaphore.hpp>
33 namespace nova {
34 namespace asynchronous_log_impl {
36 struct asynchronous_log:
37 noncopyable
39 bool log_printf(const char *fmt, ...)
41 va_list vargs;
42 va_start(vargs, fmt);
44 bool result = log_printf(fmt, vargs);
45 va_end(vargs);
46 return result;
49 bool log_printf(const char *fmt, va_list vargs)
51 std::array<char, 4096> scratchpad;
52 int print_result = vsnprintf(scratchpad.data(), scratchpad.size(), fmt, vargs);
54 if (print_result >= scratchpad.size())
55 fprintf(stderr, "warning: log message truncated");
57 return log(scratchpad.data(), print_result);
60 bool log(const char * string)
62 size_t length = strlen(string);
63 return log(string, length);
66 bool log(const char * string, size_t length)
68 size_t total_enqueued = buffer.push(string, length);
69 if (total_enqueued == 0)
70 return false;
72 sem.post();
74 if (total_enqueued == length)
75 return true;
77 string += total_enqueued;
78 length -= total_enqueued;
80 for (;;) {
81 size_t enqueued = buffer.push(string, length);
82 if (enqueued == 0)
83 continue;
85 sem.post();
87 if (enqueued == length)
88 break;
90 string += total_enqueued;
91 length -= total_enqueued;
94 return true;
97 size_t read_log(char * out_buffer, size_t size)
99 if (sem.try_wait())
100 return read(out_buffer, size);
101 else
102 return 0;
105 size_t read_log_waiting(char * out_buffer, size_t size)
107 sem.wait();
108 return read(out_buffer, size);
111 size_t read(char * out_buffer, size_t size)
113 return buffer.pop(out_buffer, size);
116 void interrrupt(void)
118 sem.post();
121 private:
122 boost::lockfree::spsc_queue<char, boost::lockfree::capacity<32768> > buffer;
123 nova::semaphore sem;
126 struct asynchronous_log_thread:
127 asynchronous_log
129 public:
130 asynchronous_log_thread(void):
131 running_flag(true), thread_(std::bind(&asynchronous_log_thread::run, this))
134 ~asynchronous_log_thread(void)
136 running_flag = false;
137 interrrupt();
138 thread_.join();
141 void run(void)
143 while (running_flag.load()) {
144 size_t read_chars = read_log_waiting(out_buffer.data(), out_buffer.size());
145 post_outbuffer(read_chars);
147 while (read_chars == out_buffer.size()) {
148 read_chars = read(out_buffer.data(), out_buffer.size());
149 post_outbuffer(read_chars);
152 size_t read_chars = read_log(out_buffer.data(), out_buffer.size());
153 post_outbuffer(read_chars);
156 void post_outbuffer(size_t read_chars)
158 for (size_t i = 0; i != read_chars; ++i)
159 putchar(out_buffer[i]);
160 fflush(stdout);
163 private:
164 boost::atomic_bool running_flag;
165 std::thread thread_;
166 std::array<char, 4096> out_buffer;
169 } /* namespace asynchronous_log_impl */
171 using asynchronous_log_impl::asynchronous_log;
172 using asynchronous_log_impl::asynchronous_log_thread;
174 } /* namespace nova */
176 #endif /* UTILITIES_ASYNCHRONOUS_LOG_HPP */