/src/dcmtk/oflog/libsrc/asyncap.cc
Line | Count | Source |
1 | | // Copyright (C) 2009-2010, Vaclav Haisman. All rights reserved. |
2 | | // |
3 | | // Redistribution and use in source and binary forms, with or without modifica- |
4 | | // tion, are permitted provided that the following conditions are met: |
5 | | // |
6 | | // 1. Redistributions of source code must retain the above copyright notice, |
7 | | // this list of conditions and the following disclaimer. |
8 | | // |
9 | | // 2. Redistributions in binary form must reproduce the above copyright notice, |
10 | | // this list of conditions and the following disclaimer in the documentation |
11 | | // and/or other materials provided with the distribution. |
12 | | // |
13 | | // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, |
14 | | // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
15 | | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
16 | | // APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
17 | | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- |
18 | | // DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
19 | | // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
20 | | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
21 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
22 | | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | | |
24 | | #include "dcmtk/oflog/config.h" |
25 | | #ifndef DCMTK_LOG4CPLUS_SINGLE_THREADED |
26 | | |
27 | | #include "dcmtk/oflog/asyncap.h" |
28 | | #include "dcmtk/oflog/spi/factory.h" |
29 | | #include "dcmtk/oflog/helpers/loglog.h" |
30 | | #include "dcmtk/oflog/helpers/property.h" |
31 | | #include "dcmtk/oflog/thread/syncpub.h" |
32 | | |
33 | | |
34 | | namespace dcmtk |
35 | | { |
36 | | namespace log4cplus |
37 | | { |
38 | | |
39 | | |
40 | | namespace |
41 | | { |
42 | | |
43 | | |
44 | | class QueueThread |
45 | | : public thread::AbstractThread |
46 | | { |
47 | | public: |
48 | | QueueThread (AsyncAppenderPtr const &, thread::QueuePtr const &); |
49 | | |
50 | | virtual void run(); |
51 | | |
52 | | private: |
53 | | AsyncAppenderPtr appenders; |
54 | | thread::QueuePtr queue; |
55 | | }; |
56 | | |
57 | | |
58 | | QueueThread::QueueThread (AsyncAppenderPtr const & aai, |
59 | | thread::QueuePtr const & q) |
60 | 0 | : appenders (aai) |
61 | 0 | , queue (q) |
62 | 0 | { } |
63 | | |
64 | | |
65 | | void |
66 | | QueueThread::run() |
67 | 0 | { |
68 | 0 | typedef log4cplus::thread::Queue::queue_storage_type ev_buf_type; |
69 | 0 | ev_buf_type ev_buf; |
70 | |
|
71 | 0 | while (true) |
72 | 0 | { |
73 | 0 | unsigned flags = queue->get_events (&ev_buf); |
74 | 0 | if (flags & thread::Queue::EVENT) |
75 | 0 | { |
76 | 0 | ev_buf_type::const_iterator const ev_buf_end = ev_buf.end (); |
77 | 0 | for (ev_buf_type::const_iterator it = ev_buf.begin (); |
78 | 0 | it != ev_buf_end; ++it) |
79 | 0 | appenders->appendLoopOnAppenders (*it); |
80 | 0 | } |
81 | |
|
82 | 0 | if (((thread::Queue::EXIT | thread::Queue::DRAIN |
83 | 0 | | thread::Queue::EVENT) & flags) |
84 | 0 | == (thread::Queue::EXIT | thread::Queue::DRAIN |
85 | 0 | | thread::Queue::EVENT)) |
86 | 0 | continue; |
87 | 0 | else if (thread::Queue::EXIT & flags) |
88 | 0 | break; |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | | |
93 | | } // namespace |
94 | | |
95 | | |
96 | | AsyncAppender::AsyncAppender (SharedAppenderPtr const & app, |
97 | | unsigned queue_len) |
98 | 0 | : queue_thread() |
99 | 0 | , queue() |
100 | 0 | { |
101 | 0 | addAppender (app); |
102 | 0 | init_queue_thread (queue_len); |
103 | 0 | } Unexecuted instantiation: dcmtk::log4cplus::AsyncAppender::AsyncAppender(dcmtk::log4cplus::helpers::SharedObjectPtr<dcmtk::log4cplus::Appender> const&, unsigned int) Unexecuted instantiation: dcmtk::log4cplus::AsyncAppender::AsyncAppender(dcmtk::log4cplus::helpers::SharedObjectPtr<dcmtk::log4cplus::Appender> const&, unsigned int) |
104 | | |
105 | | |
106 | | AsyncAppender::AsyncAppender (helpers::Properties const & props) |
107 | 0 | : queue_thread() |
108 | 0 | , queue() |
109 | 0 | { |
110 | 0 | tstring const & appender_name = |
111 | 0 | props.getProperty (DCMTK_LOG4CPLUS_TEXT ("Appender")); |
112 | 0 | if (appender_name.empty ()) |
113 | 0 | { |
114 | 0 | getErrorHandler ()->error ( |
115 | 0 | DCMTK_LOG4CPLUS_TEXT ("Unspecified appender for AsyncAppender.")); |
116 | 0 | return; |
117 | 0 | } |
118 | | |
119 | 0 | spi::AppenderFactoryRegistry & appender_registry |
120 | 0 | = spi::getAppenderFactoryRegistry (); |
121 | 0 | spi::AppenderFactory * factory = appender_registry.get (appender_name); |
122 | 0 | if (! factory) |
123 | 0 | { |
124 | 0 | tstring const err (DCMTK_LOG4CPLUS_TEXT ("AsyncAppender::AsyncAppender()") |
125 | 0 | DCMTK_LOG4CPLUS_TEXT (" - Cannot find AppenderFactory: ")); |
126 | 0 | helpers::getLogLog ().error (err + appender_name); |
127 | | // Add at least null appender so that we do not crash unexpectedly |
128 | | // elsewhere. |
129 | | // XXX: What about throwing an exception instead? |
130 | 0 | factory = appender_registry.get ( |
131 | 0 | DCMTK_LOG4CPLUS_TEXT ("log4cplus::NullAppender")); |
132 | 0 | } |
133 | |
|
134 | 0 | helpers::Properties appender_props = props.getPropertySubset ( |
135 | 0 | DCMTK_LOG4CPLUS_TEXT ("Appender.")); |
136 | 0 | addAppender (factory->createObject (appender_props)); |
137 | |
|
138 | 0 | unsigned queue_len = 100; |
139 | 0 | props.getUInt (queue_len, DCMTK_LOG4CPLUS_TEXT ("QueueLimit")); |
140 | |
|
141 | 0 | init_queue_thread (queue_len); |
142 | 0 | } Unexecuted instantiation: dcmtk::log4cplus::AsyncAppender::AsyncAppender(dcmtk::log4cplus::helpers::Properties const&) Unexecuted instantiation: dcmtk::log4cplus::AsyncAppender::AsyncAppender(dcmtk::log4cplus::helpers::Properties const&) |
143 | | |
144 | | |
145 | | AsyncAppender::~AsyncAppender () |
146 | 0 | { |
147 | 0 | destructorImpl (); |
148 | 0 | } |
149 | | |
150 | | |
151 | | void |
152 | | AsyncAppender::init_queue_thread (unsigned queue_len) |
153 | 0 | { |
154 | 0 | queue = new thread::Queue (queue_len); |
155 | 0 | queue_thread = new QueueThread (AsyncAppenderPtr (this), queue); |
156 | 0 | queue_thread->start (); |
157 | 0 | helpers::getLogLog ().debug (DCMTK_LOG4CPLUS_TEXT("Queue thread started.")); |
158 | 0 | } |
159 | | |
160 | | |
161 | | void |
162 | | AsyncAppender::close () |
163 | 0 | { |
164 | 0 | unsigned ret = queue->signal_exit (); |
165 | 0 | if (ret & (thread::Queue::ERROR_BIT | thread::Queue::ERROR_AFTER)) |
166 | 0 | getErrorHandler ()->error ( |
167 | 0 | DCMTK_LOG4CPLUS_TEXT ("Error in AsyncAppender::close")); |
168 | 0 | queue_thread->join (); |
169 | 0 | } |
170 | | |
171 | | |
172 | | void |
173 | | AsyncAppender::append (spi::InternalLoggingEvent const & ev) |
174 | 0 | { |
175 | 0 | if (queue_thread && queue_thread->isRunning ()) |
176 | 0 | { |
177 | 0 | unsigned ret = queue->put_event (ev); |
178 | 0 | if (ret & (thread::Queue::ERROR_BIT | thread::Queue::ERROR_AFTER)) |
179 | 0 | { |
180 | 0 | getErrorHandler ()->error ( |
181 | 0 | DCMTK_LOG4CPLUS_TEXT ("Error in AsyncAppender::append,") |
182 | 0 | DCMTK_LOG4CPLUS_TEXT (" event queue has been lost.")); |
183 | | // Exit the queue consumer thread without draining |
184 | | // the events queue. |
185 | 0 | queue->signal_exit (false); |
186 | 0 | queue_thread->join (); |
187 | 0 | queue_thread = 0; |
188 | 0 | queue = 0; |
189 | 0 | appendLoopOnAppenders (ev); |
190 | 0 | } |
191 | 0 | } |
192 | 0 | else |
193 | 0 | { |
194 | | // If the thread has died for any reason, fall back to synchronous |
195 | | // operation. |
196 | 0 | appendLoopOnAppenders (ev); |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | |
201 | | } // namespace log4cplus |
202 | | } // end namespace dcmtk |
203 | | |
204 | | |
205 | | #endif // #ifndef DCMTK_LOG4CPLUS_SINGLE_THREADED |