Imported Upstream version 3.0
[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 2, 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
33
34 /*
35  * This class creates the thread that reads from the ringbuffer and
36  * and writes to the file.  This is opaque to the user.
37  */
38 class gri_log_poster : public omni_thread
39 {
40   FILE                 *d_fp;
41   gr_buffer_sptr        d_writer;
42   gr_buffer_reader_sptr d_reader;
43   omni_semaphore        d_ringbuffer_ready;
44   volatile bool         d_time_to_die;
45   volatile bool         d_writer_overrun;
46
47   virtual void* run_undetached(void * arg);
48
49 public:
50   gri_log_poster(const char *filename);
51   ~gri_log_poster();
52
53   void kill() { d_time_to_die = true; post(); }
54   gr_buffer_sptr writer() const { return d_writer; }
55   void post() { d_ringbuffer_ready.post(); }
56   void note_writer_overrun() { d_writer_overrun = true; }
57 };
58
59 gri_log_poster::gri_log_poster(const char *filename)
60   : omni_thread(),
61     d_ringbuffer_ready(1, 1),           // binary semaphore
62     d_time_to_die(false),
63     d_writer_overrun(false)
64 {
65   if ((d_fp = fopen(filename, "w")) == 0){
66     perror (filename);
67     throw std::runtime_error("can't open file");
68   }
69
70   // Create a 1MB buffer.
71   d_writer = gr_make_buffer(1 * 1024 * 1024, sizeof(unsigned char));
72   d_reader = gr_buffer_add_reader(d_writer, 0);
73
74   start_undetached();  // start the thread
75 }
76
77 gri_log_poster::~gri_log_poster()
78 {
79   if (d_fp != 0){
80     fclose(d_fp);
81     d_fp = 0;
82   }
83 }
84
85 /*
86  * This is the body of the logging thread.
87  */
88 void *
89 gri_log_poster::run_undetached(void *arg)
90 {
91   int nbytes;
92
93   //fprintf(stderr, "Enter: run_undetached!\n");
94
95   while (!d_time_to_die){
96     while ((nbytes = d_reader->items_available()) > 0){
97       fwrite(d_reader->read_pointer(), 1, nbytes, d_fp);
98       d_reader->update_read_pointer(nbytes);
99     }
100     fflush(d_fp);
101     d_ringbuffer_ready.wait();
102
103     if (d_writer_overrun){
104       fputs(">>>>> gri_logger: writer overrun.  Info lost <<<<<\n", d_fp);
105       d_writer_overrun = false;
106     }
107   }
108
109   // fprintf(stderr, "Exit: run_undetached!\n");
110   return 0;
111 }
112
113 // ------------------------------------------------------------------------
114
115 static boost::weak_ptr<gri_logger> s_singleton;  // weak pointer IQ test ;-)
116 static omni_mutex s_singleton_mutex;
117
118 gri_logger_sptr
119 gri_logger::singleton()
120 {
121   omni_mutex_lock l(s_singleton_mutex);
122   gri_logger_sptr r;
123
124   if (r = s_singleton.lock())
125     return r;
126
127   r = gri_logger_sptr(new gri_logger("gri_logger.log"));
128   s_singleton = r;
129   return r;
130 }
131   
132
133 gri_logger::gri_logger(const char *filename)
134 {
135   d_poster = new gri_log_poster(filename);
136 }
137
138 gri_logger::~gri_logger()
139 {
140   d_poster->kill();
141   d_poster->join(NULL);
142 }
143
144 void
145 gri_logger::write(const void *buf, size_t count)
146 {
147   omni_mutex_lock l(d_write_mutex);
148   gr_buffer_sptr writer = d_poster->writer();
149   
150   // either write it all, or drop it on the ground
151   if (count <= (size_t) writer->space_available()){
152     memcpy(writer->write_pointer(), buf, count);
153     writer->update_write_pointer(count);
154     d_poster->post();
155   }
156   else {
157     d_poster->note_writer_overrun();
158   }
159 }
160
161 void
162 gri_logger::printf(const char *format, ...)
163 {
164   va_list       ap;
165   char          buf[4096];
166   int           n;
167   
168   va_start(ap, format);
169   n = vsnprintf(buf, sizeof(buf), format, ap);
170   va_end(ap);
171   if (n > -1 && n < (ssize_t) sizeof(buf))
172     write(buf, n);
173 }