MythTV  0.26-pre
ringbuffer.c
Go to the documentation of this file.
00001 /*
00002  * ringbuffer.c
00003  *        
00004  *
00005  * Copyright (C) 2003 Marcus Metzler <mocm@metzlerbros.de>
00006  *                    Metzler Brothers Systementwicklung GbR
00007  * Changes to use MythTV logging
00008  * Copyright (C) 2011 Gavin Hurlbut <ghurlbut@mythtv.org>
00009  *
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License
00012  * as published by the Free Software Foundation; either version 2
00013  * of the License, or (at your option) any later version.
00014  *
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * General Public License for more details.
00020  *
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00025  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00026  *
00027  */
00028 
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include "ringbuffer.h"
00032 #include "pes.h"
00033 
00034 #include "mythlogging.h"
00035 
00036 #define DEBUG 1
00037 int ring_init (ringbuffer *rbuf, int size)
00038 {
00039         if (size > 0){
00040                 rbuf->size = size;
00041                 if( !(rbuf->buffer = (uint8_t *) malloc(sizeof(uint8_t)*size)) ){
00042                         LOG(VB_GENERAL, LOG_ERR,
00043                             "Not enough memory for ringbuffer");
00044                         return -1;
00045                 }
00046         } else {
00047                 LOG(VB_GENERAL, LOG_ERR, "Wrong size for ringbuffer");
00048                 return -1;
00049         }
00050         rbuf->read_pos = 0;     
00051         rbuf->write_pos = 0;
00052         return 0;
00053 }
00054 
00055 int ring_reinit (ringbuffer *rbuf, int size)
00056 {
00057         if (size > (int)(rbuf->size)) {
00058                 uint8_t *tmpalloc = (uint8_t *) realloc(rbuf->buffer,
00059                                                         sizeof(uint8_t)*size);
00060                 if (! tmpalloc)
00061                         return -1;
00062                 rbuf->buffer = tmpalloc;
00063                 if (rbuf->write_pos < rbuf->read_pos)
00064                 {
00065                         unsigned int delta = size - rbuf->size;
00066                         memmove(rbuf->buffer + rbuf->read_pos + delta,
00067                                 rbuf->buffer + rbuf->read_pos,
00068                                 rbuf->size - rbuf->read_pos);
00069                         rbuf->read_pos += delta;
00070                 }
00071                 rbuf->size = size;
00072         }
00073         return 0;
00074 }
00075 void ring_clear(ringbuffer *rbuf)
00076 {
00077         rbuf->read_pos = 0;     
00078         rbuf->write_pos = 0;
00079 }
00080 
00081 
00082 
00083 void ring_destroy(ringbuffer *rbuf)
00084 {
00085         free(rbuf->buffer);
00086 }
00087 
00088 
00089 int ring_write(ringbuffer *rbuf, uint8_t *data, int count)
00090 {
00091 
00092         int free, pos, rest;
00093 
00094         if (count <=0 ) return 0;
00095         pos  = rbuf->write_pos;
00096         rest = rbuf->size - pos;
00097         free = ring_free(rbuf);
00098 
00099         if ( free < count ){
00100                 if (DEBUG)
00101                         LOG(VB_GENERAL, LOG_ERR,
00102                             "ringbuffer overflow %d<%d %d",
00103                                 free, count, rbuf->size);
00104                 return FULL_BUFFER;
00105         }
00106         
00107         if (count >= rest){
00108                 memcpy (rbuf->buffer+pos, data, rest);
00109                 if (count - rest)
00110                         memcpy (rbuf->buffer, data+rest, count - rest);
00111                 rbuf->write_pos = count - rest;
00112         } else {
00113                 memcpy (rbuf->buffer+pos, data, count);
00114                 rbuf->write_pos += count;
00115         }
00116 
00117         if (DEBUG>1)
00118                 LOG(VB_GENERAL, LOG_ERR, "Buffer empty %.2f%%",
00119                      ring_free(rbuf)*100.0/rbuf->size);
00120         return count;
00121 }
00122 
00123 int ring_peek(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
00124 {
00125 
00126         unsigned int avail, pos, rest;
00127 
00128         if (off+count > rbuf->size || off+count >ring_avail(rbuf))
00129                 return -1;
00130         pos  = (rbuf->read_pos+off)%rbuf->size;
00131         rest = rbuf->size - pos ;
00132         avail = ring_avail(rbuf); 
00133 
00134         
00135         if ( avail < count ){
00136 #if 0
00137                 if (DEBUG)
00138                         LOG(VB_GENERAL, LOG_ERR,
00139                             "ringbuffer peek underflow %d<%d %d %d",
00140                                 avail, count, pos, rbuf->write_pos);
00141 #endif
00142                 return EMPTY_BUFFER;
00143         }
00144 
00145         if ( count < rest ){
00146                 memcpy(data, rbuf->buffer+pos, count);
00147         } else {
00148                 memcpy(data, rbuf->buffer+pos, rest);
00149                 if ( count - rest)
00150                         memcpy(data+rest, rbuf->buffer, count - rest);
00151         }
00152 
00153         return count;
00154 }
00155 
00156 int ring_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
00157 {
00158 
00159         unsigned int avail, pos, rest;
00160 
00161         if (off+count > rbuf->size || off+count >ring_avail(rbuf))
00162                 return -1;
00163         pos  = (rbuf->read_pos+off)%rbuf->size;
00164         rest = rbuf->size - pos ;
00165         avail = ring_avail(rbuf); 
00166 
00167         
00168         if ( avail < count ){
00169 #if 0
00170                 if (DEBUG)
00171                         LOG(VB_GENERAL, LOG_ERR,
00172                             "ringbuffer peek underflow %d<%d %d %d",
00173                                 avail, count, pos, rbuf->write_pos);
00174 #endif
00175                 return EMPTY_BUFFER;
00176         }
00177 
00178         if ( count < rest ){
00179                 memcpy(rbuf->buffer+pos, data, count);
00180         } else {
00181                 memcpy(rbuf->buffer+pos, data, rest);
00182                 if ( count - rest)
00183                         memcpy(rbuf->buffer, data+rest, count - rest);
00184         }
00185 
00186         return count;
00187 }
00188 
00189 int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
00190 {
00191 
00192         int avail, pos, rest;
00193 
00194         if (count <=0 ) return 0;
00195         pos  = rbuf->read_pos;
00196         rest = rbuf->size - pos;
00197         avail = ring_avail(rbuf);
00198         
00199         if ( avail < count ){
00200 #if 0
00201                 if (DEBUG)
00202                         LOG(VB_GENERAL, LOG_ERR,
00203                             "ringbuffer underflow %d<%d %d \n",
00204                                 avail, count, rbuf->size);
00205 #endif
00206                 return EMPTY_BUFFER;
00207         }
00208 
00209         if ( count < rest ){
00210                 memcpy(data, rbuf->buffer+pos, count);
00211                 rbuf->read_pos += count;
00212         } else {
00213                 memcpy(data, rbuf->buffer+pos, rest);
00214                 if ( count - rest)
00215                         memcpy(data+rest, rbuf->buffer, count - rest);
00216                 rbuf->read_pos = count - rest;
00217         }
00218 
00219         if (DEBUG>1)
00220                 LOG(VB_GENERAL, LOG_ERR, "Buffer empty %.2f%%",
00221                      ring_free(rbuf)*100.0/rbuf->size);
00222         return count;
00223 }
00224 
00225 int ring_skip(ringbuffer *rbuf, int count)
00226 {
00227 
00228         int avail, pos, rest;
00229 
00230         if (count <=0 ) return -1;
00231         pos  = rbuf->read_pos;
00232         rest = rbuf->size - pos;
00233         avail = ring_avail(rbuf);
00234 
00235         if ( avail < count ){
00236 #if 0
00237                 LOG(VB_GENERAL, LOG_ERR,
00238                     "ringbuffer skip underflow %d<%d %d %d\n",
00239                         avail, count, pos, rbuf->write_pos);
00240 #endif
00241                 return EMPTY_BUFFER;
00242         }
00243         if ( count < rest ){
00244                 rbuf->read_pos += count;
00245         } else {
00246                 rbuf->read_pos = count - rest;
00247         }
00248 
00249         if (DEBUG>1)
00250                 LOG(VB_GENERAL, LOG_ERR, "Buffer empty %.2f%%",
00251                      ring_free(rbuf)*100.0/rbuf->size);
00252         return count;
00253 }
00254 
00255 
00256 
00257 int ring_write_file(ringbuffer *rbuf, int fd, int count)
00258 {
00259 
00260         int free, pos, rest, rr;
00261 
00262         if (count <=0 ) return 0;
00263         pos  = rbuf->write_pos;
00264         rest = rbuf->size - pos;
00265         free = ring_free(rbuf);
00266 
00267         if ( free < count ){
00268                 if (DEBUG)
00269                         LOG(VB_GENERAL, LOG_ERR,
00270                             "ringbuffer overflow %d<%d %d %d\n",
00271                                 free, count, pos, rbuf->read_pos);
00272                 return FULL_BUFFER;
00273         }
00274         
00275         if (count >= rest){
00276                 rr = read (fd, rbuf->buffer+pos, rest);
00277                 if (rr == rest && count - rest)
00278                         rr += read (fd, rbuf->buffer, count - rest);
00279                 if (rr >=0)
00280                         rbuf->write_pos = (pos + rr) % rbuf->size;
00281         } else {
00282                 rr = read (fd, rbuf->buffer+pos, count);
00283                 if (rr >=0)
00284                         rbuf->write_pos += rr;
00285         }
00286 
00287         if (DEBUG>1)
00288                 LOG(VB_GENERAL, LOG_ERR, "Buffer empty %.2f%%",
00289                    ring_free(rbuf)*100.0/rbuf->size);
00290         return rr;
00291 }
00292 
00293 
00294 
00295 int ring_read_file(ringbuffer *rbuf, int fd, int count)
00296 {
00297 
00298         int avail, pos, rest, rr;
00299 
00300         if (count <=0 ) return -1;
00301         pos  = rbuf->read_pos;
00302         rest = rbuf->size - pos;
00303         avail = ring_avail(rbuf);
00304 
00305         if ( avail < count ){
00306 #if 0
00307                 if (DEBUG)
00308                         LOG(VB_GENERAL, LOG_ERR,
00309                             "ringbuffer underflow %d<%d %d %d",
00310                                 avail, count, pos, rbuf->write_pos);
00311 #endif
00312                 return EMPTY_BUFFER;
00313         }
00314 
00315         if (count >= rest){
00316                 rr = write (fd, rbuf->buffer+pos, rest);
00317                 if (rr == rest && count - rest)
00318                         rr += write (fd, rbuf->buffer, count - rest);
00319                 if (rr >=0)
00320                         rbuf->read_pos = (pos + rr) % rbuf->size;
00321         } else {
00322                 rr = write (fd, rbuf->buffer+pos, count);
00323                 if (rr >=0)
00324                         rbuf->read_pos += rr;
00325         }
00326 
00327 
00328         if (DEBUG>1)
00329                 LOG(VB_GENERAL, LOG_ERR, "Buffer empty %.2f%%",
00330                      ring_free(rbuf)*100.0/rbuf->size);
00331         return rr;
00332 }
00333 
00334 
00335 static void show(uint8_t *buf, int length)
00336 {
00337         int i,j,r;
00338         uint8_t temp[8];
00339         uint8_t buffer[100];
00340         buffer[0] = '\0';
00341 
00342         for (i=0; i<length; i+=16){
00343                 for (j=0; j < 8 && j+i<length; j++)
00344                 {
00345                         sprintf(temp, "0x%02x ", (int)(buf[i+j]));
00346                         strcat(buffer, temp);
00347                 }
00348                 for (r=j; r<8; r++)                     
00349                         strcat(buffer, "     ");
00350 
00351                 strcat(buffer,"  ");
00352 
00353                 for (j=8; j < 16 && j+i<length; j++)
00354                 {
00355                         sprintf(temp, "0x%02x ", (int)(buf[i+j]));
00356                         strcat(buffer, temp);
00357                 }
00358                 for (r=j; r<16; r++)                    
00359                         strcat(buffer, "     ");
00360 
00361                 for (j=0; j < 16 && j+i<length; j++){
00362                         switch(buf[i+j]){
00363                         case '0'...'Z':
00364                         case 'a'...'z':
00365                                 sprintf(temp, "%c", buf[i+j]);
00366                                 break;
00367                         default:
00368                                 sprintf(temp, ".");
00369                         }
00370                         strcat(buffer, temp);
00371                 }
00372                 LOG(VB_GENERAL, LOG_INFO, buffer);
00373         }
00374 }
00375 
00376 void ring_show(ringbuffer *rbuf, unsigned int count, uint32_t off)
00377 {
00378 
00379         unsigned int avail, pos, rest;
00380 
00381         if (off+count > rbuf->size || off+count >ring_avail(rbuf))
00382                 return;
00383         pos  = (rbuf->read_pos+off)%rbuf->size;
00384         rest = rbuf->size - pos ;
00385         avail = ring_avail(rbuf); 
00386 
00387         
00388         if ( avail < count ){
00389 #if 0
00390                 if (DEBUG)
00391                         LOG(VB_GENERAL, LOG_ERR,
00392                             "ringbuffer peek underflow %d<%d %d %d\n",
00393                                 avail, count, pos, rbuf->write_pos);
00394 #endif
00395                 return;
00396         }
00397 
00398         if ( count < rest ){
00399                 show(rbuf->buffer+pos, count);
00400         } else {
00401                 show(rbuf->buffer+pos, rest);
00402                 if ( count - rest)
00403                         show(rbuf->buffer, count - rest);
00404         }
00405 }
00406 
00407 
00408 int dummy_init(dummy_buffer *dbuf, int s)
00409 {
00410         dbuf->size = s;
00411         dbuf->fill = 0;
00412         if (ring_init(&dbuf->time_index, DBUF_INDEX*sizeof(uint64_t)) < 0)
00413                 return -1;
00414         if (ring_init(&dbuf->data_index, DBUF_INDEX*sizeof(int32_t)) < 0)
00415                 return -1;
00416 
00417         return 0;
00418 }
00419 
00420 void dummy_destroy(dummy_buffer *dbuf)
00421 {
00422         ring_destroy(&dbuf->time_index);
00423         ring_destroy(&dbuf->data_index);
00424 }
00425 
00426 void dummy_clear(dummy_buffer *dbuf)
00427 {
00428         dbuf->fill = 0;
00429         ring_clear(&dbuf->time_index);
00430         ring_clear(&dbuf->data_index);
00431 }
00432 
00433 int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
00434 {
00435         if (dummy_space(dbuf) < size) return -1;
00436 #if 0
00437         LOG(VB_GENERAL, LOG_INFO, "add %d ", dummy_space(dbuf));
00438 #endif
00439         dbuf->fill += size;
00440         if (ring_write(&dbuf->time_index, (uint8_t *)&time, sizeof(uint64_t)) < 0) 
00441                 return -2;
00442         if (ring_write(&dbuf->data_index, (uint8_t *)&size, sizeof(uint32_t)) < 0) 
00443                 return -3;
00444 #if 0
00445         LOG(VB_GENERAL, LOG_INFO, " - %d = "%d", size, dummy_space(dbuf));
00446 #endif
00447         return size;
00448 }
00449 
00450 int dummy_delete(dummy_buffer *dbuf, uint64_t time)
00451 {
00452         uint64_t rtime;
00453         uint32_t size;
00454         int ex=0;
00455         uint32_t dsize=0;
00456 
00457         do {
00458                 if (ring_peek(&dbuf->time_index,(uint8_t *) &rtime, 
00459                               sizeof(uint64_t), 0)<0){
00460                         if (dsize) break;
00461                         else return -1;
00462                 }
00463                 if (ptscmp(rtime,time) < 0){
00464                         ring_read(&dbuf->time_index,(uint8_t *) &rtime, 
00465                                   sizeof(uint64_t));
00466                         ring_read(&dbuf->data_index,(uint8_t *) &size, 
00467                                   sizeof(uint32_t));
00468                         dsize += size;
00469                 } else ex = 1;
00470         } while (!ex);
00471 #if 0
00472         LOG(VB_GENERAL, LOG_INFO, "delete %d ", dummy_space(dbuf));
00473 #endif
00474         dbuf->fill -= dsize;
00475 #if 0
00476         LOG(VB_GENERAL, LOG_INFO, " + %d = %d", dsize, dummy_space(dbuf));
00477 #endif
00478 
00479         return dsize;
00480 }
00481 
00482 static void dummy_print(dummy_buffer *dbuf)
00483 {
00484    int i;
00485    uint64_t rtime;
00486    uint32_t size;
00487    int avail = ring_avail(&dbuf->time_index) / sizeof(uint64_t);
00488    for(i = 0; i < avail; i++) {
00489        ring_peek(&dbuf->time_index,(uint8_t *) &rtime, 
00490                               sizeof(uint64_t), i * sizeof(uint64_t));
00491        ring_peek(&dbuf->data_index,(uint8_t *) &size, 
00492                               sizeof(uint32_t), i * sizeof(uint32_t));
00493 
00494        LOG(VB_GENERAL, LOG_INFO, "%d : %llu %u", i,
00495            (long long unsigned int)rtime, size);
00496    }
00497    LOG(VB_GENERAL, LOG_INFO, "Used: %d Free: %d data-free: %d", avail,
00498        1000-avail, dbuf->size - dbuf->fill);
00499 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends