Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / lib / io / gri_logger.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <gri_logger.h>
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include <stdexcept>
31 #include <boost/weak_ptr.hpp>
32 #include <string.h>
33
34
35 /*
36  * This class creates the thread that reads from the ringbuffer and
37  * and writes to the file.  This is opaque to the user.
38  */
39 class gri_log_poster : public omni_thread
40 {
41   FILE                 *d_fp;
42   gr_buffer_sptr        d_writer;
43   gr_buffer_reader_sptr d_reader;
44   omni_semaphore        d_ringbuffer_ready;
45   volatile bool         d_time_to_die;
46   volatile bool         d_writer_overrun;
47
48   virtual void* run_undetached(void * arg);
49
50 public:
51   gri_log_poster(const char *filename);
52   ~gri_log_poster();
53
54   void kill() { d_time_to_die = true; post(); }
55   gr_buffer_sptr writer() const { return d_writer; }
56   void post() { d_ringbuffer_ready.post(); }
57   void note_writer_overrun() { d_writer_overrun = true; }
58 };
59
60 gri_log_poster::gri_log_poster(const char *filename)
61   : omni_thread(),
62     d_ringbuffer_ready(1, 1),           // binary semaphore
63     d_time_to_die(false),
64     d_writer_overrun(false)
65 {
66   if ((d_fp = fopen(filename, "w")) == 0){
67     perror (filename);
68     throw std::runtime_error("can't open file");
69   }
70
71   // Create a 1MB buffer.
72   d_writer = gr_make_buffer(1 * 1024 * 1024, sizeof(unsigned char));
73   d_reader = gr_buffer_add_reader(d_writer, 0);
74
75   start_undetached();  // start the thread
76 }
77
78 gri_log_poster::~gri_log_poster()
79 {
80   if (d_fp != 0){
81     fclose(d_fp);
82     d_fp = 0;
83   }
84 }
85
86 /*
87  * This is the body of the logging thread.
88  */
89 void *
90 gri_log_poster::run_undetached(void *arg)
91 {
92   int nbytes;
93
94   //fprintf(stderr, "Enter: run_undetached!\n");
95
96   while (!d_time_to_die){
97     while ((nbytes = d_reader->items_available()) > 0){
98       fwrite(d_reader->read_pointer(), 1, nbytes, d_fp);
99       d_reader->update_read_pointer(nbytes);
100     }
101     fflush(d_fp);
102     d_ringbuffer_ready.wait();
103
104     if (d_writer_overrun){
105       fputs(">>>>> gri_logger: writer overrun.  Info lost <<<<<\n", d_fp);
106       d_writer_overrun = false;
107     }
108   }
109
110   // fprintf(stderr, "Exit: run_undetached!\n");
111   return 0;
112 }
113
114 // ------------------------------------------------------------------------
115
116 static boost::weak_ptr<gri_logger> s_singleton;  // weak pointer IQ test ;-)
117 static omni_mutex s_singleton_mutex;
118
119 gri_logger_sptr
120 gri_logger::singleton()
121 {
122   omni_mutex_lock l(s_singleton_mutex);
123   gri_logger_sptr r;
124
125   if (r = s_singleton.lock())
126     return r;
127
128   r = gri_logger_sptr(new gri_logger("gri_logger.log"));
129   s_singleton = r;
130   return r;
131 }
132   
133
134 gri_logger::gri_logger(const char *filename)
135 {
136   d_poster = new gri_log_poster(filename);
137 }
138
139 gri_logger::~gri_logger()
140 {
141   d_poster->kill();
142   d_poster->join(NULL);
143 }
144
145 void
146 gri_logger::write(const void *buf, size_t count)
147 {
148   omni_mutex_lock l(d_write_mutex);
149   gr_buffer_sptr writer = d_poster->writer();
150   
151   // either write it all, or drop it on the ground
152   if (count <= (size_t) writer->space_available()){
153     memcpy(writer->write_pointer(), buf, count);
154     writer->update_write_pointer(count);
155     d_poster->post();
156   }
157   else {
158     d_poster->note_writer_overrun();
159   }
160 }
161
162 void
163 gri_logger::printf(const char *format, ...)
164 {
165   va_list       ap;
166   char          buf[4096];
167   int           n;
168   
169   va_start(ap, format);
170   n = vsnprintf(buf, sizeof(buf), format, ap);
171   va_end(ap);
172   if (n > -1 && n < (ssize_t) sizeof(buf))
173     write(buf, n);
174 }