| 1 | /*************************************************************************** |
|---|
| 2 | * (c)2005-2011 Broadcom Corporation |
|---|
| 3 | * |
|---|
| 4 | * This program is the proprietary software of Broadcom Corporation and/or its licensors, |
|---|
| 5 | * and may only be used, duplicated, modified or distributed pursuant to the terms and |
|---|
| 6 | * conditions of a separate, written license agreement executed between you and Broadcom |
|---|
| 7 | * (an "Authorized License"). Except as set forth in an Authorized License, Broadcom grants |
|---|
| 8 | * no license (express or implied), right to use, or waiver of any kind with respect to the |
|---|
| 9 | * Software, and Broadcom expressly reserves all rights in and to the Software and all |
|---|
| 10 | * intellectual property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU |
|---|
| 11 | * HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY |
|---|
| 12 | * NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. |
|---|
| 13 | * |
|---|
| 14 | * Except as expressly set forth in the Authorized License, |
|---|
| 15 | * |
|---|
| 16 | * 1. This program, including its structure, sequence and organization, constitutes the valuable trade |
|---|
| 17 | * secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof, |
|---|
| 18 | * and to use this information only in connection with your use of Broadcom integrated circuit products. |
|---|
| 19 | * |
|---|
| 20 | * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" |
|---|
| 21 | * AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR |
|---|
| 22 | * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO |
|---|
| 23 | * THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES |
|---|
| 24 | * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, |
|---|
| 25 | * LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION |
|---|
| 26 | * OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF |
|---|
| 27 | * USE OR PERFORMANCE OF THE SOFTWARE. |
|---|
| 28 | * |
|---|
| 29 | * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS |
|---|
| 30 | * LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR |
|---|
| 31 | * EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR |
|---|
| 32 | * USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF |
|---|
| 33 | * THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT |
|---|
| 34 | * ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE |
|---|
| 35 | * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF |
|---|
| 36 | * ANY LIMITED REMEDY. |
|---|
| 37 | * |
|---|
| 38 | * $brcm_Workfile: nexus_file_fifo.c $ |
|---|
| 39 | * $brcm_Revision: 15 $ |
|---|
| 40 | * $brcm_Date: 6/28/11 11:07a $ |
|---|
| 41 | * |
|---|
| 42 | * Module Description: |
|---|
| 43 | * |
|---|
| 44 | * Revision History: |
|---|
| 45 | * |
|---|
| 46 | * $brcm_Log: /nexus/modules/file/src/nexus_file_fifo.c $ |
|---|
| 47 | * |
|---|
| 48 | * 15 6/28/11 11:07a vsilyaev |
|---|
| 49 | * SW7420-1139: Trim of the metadata offset |
|---|
| 50 | * |
|---|
| 51 | * 14 5/26/11 7:01p vsilyaev |
|---|
| 52 | * SW7335-1249: Added option to pereiodically write metadata into a disk |
|---|
| 53 | * file |
|---|
| 54 | * |
|---|
| 55 | * 13 2/25/11 12:47p erickson |
|---|
| 56 | * SW7125-818: use BNAV_GetEntrySize |
|---|
| 57 | * |
|---|
| 58 | * 12 5/24/10 10:49a jtna |
|---|
| 59 | * SW7550-439: Coverity Defect ID:21994 ATOMICITY |
|---|
| 60 | * |
|---|
| 61 | * 11 4/2/10 2:37p erickson |
|---|
| 62 | * SW7405-3833: nexus_file_pvr.h is now part of the public API |
|---|
| 63 | * |
|---|
| 64 | * 10 11/9/09 6:49p mphillip |
|---|
| 65 | * SW7405-3361: Fix header zeroing when opening for playback without |
|---|
| 66 | * record |
|---|
| 67 | * |
|---|
| 68 | * 9 9/16/09 6:27p mphillip |
|---|
| 69 | * SW7405-3035: Check in I/O cleanup changes |
|---|
| 70 | * |
|---|
| 71 | * 8 9/15/09 11:19a mphillip |
|---|
| 72 | * SWDEPRECATED-3998: Set trim position to the first available offset when |
|---|
| 73 | * requested trim location is earlier. |
|---|
| 74 | * |
|---|
| 75 | * 7 6/4/09 5:01p erickson |
|---|
| 76 | * PR54129: align file to 188 for non O_DIRECT. don't align trim offset if |
|---|
| 77 | * non O DIRECT. fix DBG. |
|---|
| 78 | * |
|---|
| 79 | * 6 3/16/09 10:51a vsilyaev |
|---|
| 80 | * PR 52405: Fixed race condition in fifo_read |
|---|
| 81 | * |
|---|
| 82 | * 5 3/5/09 5:46p vsilyaev |
|---|
| 83 | * PR 52579: Updated circular FIFO/timeshifting code |
|---|
| 84 | * |
|---|
| 85 | * 4 1/27/09 10:53a erickson |
|---|
| 86 | * PR50367: added memset |
|---|
| 87 | * |
|---|
| 88 | * 3 6/4/08 1:33p rjlewis |
|---|
| 89 | * PR40352: off_t is 32-bits in VxWorks -- use 64. |
|---|
| 90 | * |
|---|
| 91 | * 2 5/12/08 1:27p vsilyaev |
|---|
| 92 | * PR 41567: Use NULL pid (0x1FFF) for video, to make NAV Player happy |
|---|
| 93 | * |
|---|
| 94 | * 1 1/18/08 2:16p jgarrett |
|---|
| 95 | * PR 38808: Merging to main branch |
|---|
| 96 | * |
|---|
| 97 | * Nexus_Devel/2 11/13/07 1:00p vsilyaev |
|---|
| 98 | * PR 37015: Improved use of O_DIRECT in API |
|---|
| 99 | * |
|---|
| 100 | * $old_brcm_Log: /BSEAV/api/src/pvr/bsettop_fileio_fifo.c $ |
|---|
| 101 | * |
|---|
| 102 | * 23 11/8/07 2:16p ahulse |
|---|
| 103 | * PR36192: Set up a trim gap so that bcmplayer and other apps never read |
|---|
| 104 | * from index to be trimmed |
|---|
| 105 | * |
|---|
| 106 | * 22 11/1/07 12:10p jackli |
|---|
| 107 | * PR36646: suppress BDBG_MSG_IO |
|---|
| 108 | * |
|---|
| 109 | * 21 10/25/07 2:23p jtna |
|---|
| 110 | * PR35936: Coverity Defect ID:3993 NULL_RETURNS |
|---|
| 111 | * |
|---|
| 112 | * 20 4/12/07 1:58p jackli |
|---|
| 113 | * PR29779: change bpvrfifo_signature |
|---|
| 114 | * |
|---|
| 115 | * 19 4/12/07 1:43p jackli |
|---|
| 116 | * PR29779: error when timeshift buffer > 4G |
|---|
| 117 | * |
|---|
| 118 | * 18 10/4/06 2:02p vsilyaev |
|---|
| 119 | * PR 23826: Added function to initialize bplayback_file structure |
|---|
| 120 | * |
|---|
| 121 | * 17 8/3/06 5:37p rjlewis |
|---|
| 122 | * PR23249: compiler warnings. |
|---|
| 123 | * |
|---|
| 124 | * 16 7/31/06 5:52p jrubio |
|---|
| 125 | * PR22697: Do not open read Index descriptor with O_DIRECT flag. |
|---|
| 126 | * |
|---|
| 127 | * 15 4/7/06 4:50p vsilyaev |
|---|
| 128 | * PR 20680: More fixes in removing bpvr_buf |
|---|
| 129 | * |
|---|
| 130 | * 14 4/7/06 3:50p vsilyaev |
|---|
| 131 | * PR 20680: Added bfile library |
|---|
| 132 | * |
|---|
| 133 | * 13 4/4/06 1:06p mphillip |
|---|
| 134 | * PR20605: Fix a missing free. |
|---|
| 135 | * |
|---|
| 136 | * 12 3/29/06 8:13p vle |
|---|
| 137 | * PR 20512: correct assertion condition when call bpvrfifo_write_release. |
|---|
| 138 | * |
|---|
| 139 | * 10 3/15/06 4:47p mphillip |
|---|
| 140 | * PR18183: Minor typo in previous checkin |
|---|
| 141 | * |
|---|
| 142 | * 9 3/15/06 4:45p mphillip |
|---|
| 143 | * PR18183: Clear the new file structure prior to use. |
|---|
| 144 | * |
|---|
| 145 | * 8 3/7/06 10:06a erickson |
|---|
| 146 | * PR19853: use BNAV_AVC_Entry for VC1 PES |
|---|
| 147 | * |
|---|
| 148 | * 7 12/23/05 4:10p vsilyaev |
|---|
| 149 | * PR 18183: Renamed API functions |
|---|
| 150 | * |
|---|
| 151 | * 5 12/19/05 3:22p rjlewis |
|---|
| 152 | * PR18183: vxworks doesn't have <sys/fcntl.h> |
|---|
| 153 | * |
|---|
| 154 | * 4 11/30/05 3:13p vsilyaev |
|---|
| 155 | * PR 18183: Improved FIFO file support |
|---|
| 156 | * |
|---|
| 157 | * 3 11/21/05 3:42p vsilyaev |
|---|
| 158 | * PR 18183: Renamed size function to bounds, so it would remain useful |
|---|
| 159 | * with trimmed files |
|---|
| 160 | * |
|---|
| 161 | * 2 11/18/05 2:27p vsilyaev |
|---|
| 162 | * PR 18183: Added periodic trimmer |
|---|
| 163 | * |
|---|
| 164 | * 1 11/17/05 4:22p vsilyaev |
|---|
| 165 | * PR 18183: Added circular(FIFO) file |
|---|
| 166 | * |
|---|
| 167 | ***************************************************************************/ |
|---|
| 168 | #include "nexus_file_module.h" |
|---|
| 169 | #include "bstd.h" |
|---|
| 170 | #include "bkni.h" |
|---|
| 171 | #include "bkni_multi.h" |
|---|
| 172 | #include "blst_queue.h" |
|---|
| 173 | #include "bcmplayer.h" |
|---|
| 174 | #include "bcmindexer.h" |
|---|
| 175 | #include "bfile_io.h" |
|---|
| 176 | #include "nexus_file_pvr.h" |
|---|
| 177 | #include "nexus_file_types.h" |
|---|
| 178 | #include "nexus_file_posix.h" |
|---|
| 179 | |
|---|
| 180 | BDBG_MODULE(fileio_fifo); |
|---|
| 181 | |
|---|
| 182 | |
|---|
| 183 | |
|---|
| 184 | struct bpvrfifo_entry { |
|---|
| 185 | off_t size; /* size of the entry */ |
|---|
| 186 | off_t voff; /* file 'virtual' offset */ |
|---|
| 187 | off_t doff; /* disk 'physical' offset */ |
|---|
| 188 | }; |
|---|
| 189 | |
|---|
| 190 | struct bpvrfifo_signature { |
|---|
| 191 | char signature[16]; |
|---|
| 192 | }; |
|---|
| 193 | |
|---|
| 194 | static const struct bpvrfifo_signature bpvrfifo_signature = |
|---|
| 195 | { |
|---|
| 196 | "bpvrFiFo 0.21" |
|---|
| 197 | }; |
|---|
| 198 | static void bfile_fifo_write_snapshot_locked(struct NEXUS_FifoRecord *file); |
|---|
| 199 | |
|---|
| 200 | |
|---|
| 201 | #define BFIFO_N_ENTRYS 5 |
|---|
| 202 | struct bpvrfifo_header { |
|---|
| 203 | union { |
|---|
| 204 | struct { |
|---|
| 205 | struct bpvrfifo_signature signature; |
|---|
| 206 | struct bpvrfifo_entry entrys[BFIFO_N_ENTRYS+1]; |
|---|
| 207 | } h; |
|---|
| 208 | uint8_t buf[512]; /* for performance reasons header shall be multiplier of the FS block size */ |
|---|
| 209 | } data; /* this is persistent portion of index (e.g. part that is saved on the disk */ |
|---|
| 210 | /* we use dual lock scheme, lock is acquired every time when header table is accessed, and busy flag is set wherever there is an active transaction, in this manner we allow simultaneous read and write transactions, and effectively serialize trim with both read and write */ |
|---|
| 211 | BKNI_MutexHandle lock; |
|---|
| 212 | unsigned busy; /* busy counter, if busy > 0 then there is an active write or read, and trim has to fail */ |
|---|
| 213 | unsigned prev_trim; /* previously trimmed value */ |
|---|
| 214 | unsigned trim_gap; /* Gap between real start of file and next trim point */ |
|---|
| 215 | }; |
|---|
| 216 | #define B_ENTRY(f,i) (&(f)->header->data.h.entrys[(i)]) |
|---|
| 217 | #define b_lock(x) BKNI_AcquireMutex(x->header->lock) |
|---|
| 218 | #define b_unlock(x) BKNI_ReleaseMutex(x->header->lock) |
|---|
| 219 | |
|---|
| 220 | struct bfile_io_write_fifo { |
|---|
| 221 | struct bfile_io_write self; |
|---|
| 222 | struct bfile_io_write_posix data; |
|---|
| 223 | struct bpvrfifo_header *header; |
|---|
| 224 | struct bpvrfifo_header _header; |
|---|
| 225 | off_t offset; /* current virtual offset, also known as a file size */ |
|---|
| 226 | off_t size; /* size of the file on a disk */ |
|---|
| 227 | off_t start; /* offset, where writeable area begins */ |
|---|
| 228 | unsigned ref_cnt; /* number of references, including itself */ |
|---|
| 229 | struct NEXUS_FifoRecord *writeSnapshotFile; |
|---|
| 230 | }; |
|---|
| 231 | |
|---|
| 232 | struct bfile_io_read_fifo { |
|---|
| 233 | struct bfile_io_read self; |
|---|
| 234 | struct bfile_io_read_posix data; |
|---|
| 235 | struct bpvrfifo_header *header; |
|---|
| 236 | off_t cur_pos; /* current virtual offset */ |
|---|
| 237 | struct bfile_io_write_fifo *writer; |
|---|
| 238 | }; |
|---|
| 239 | |
|---|
| 240 | #define B_ENTRY_CLEAR(f,i) do{ B_ENTRY(f,i)->doff=-1;B_ENTRY(f,i)->voff=0;B_ENTRY(f,i)->size=0;}while(0) |
|---|
| 241 | #define B_ENTRY_IS_EMPTY(f,i) (B_ENTRY(f,i)->doff==-1) |
|---|
| 242 | |
|---|
| 243 | #if 0 |
|---|
| 244 | #define BDBG_MSG_IO(i, x) BDBG_INSTANCE_MSG(i, x) |
|---|
| 245 | #else |
|---|
| 246 | #define BDBG_MSG_IO(i, x) |
|---|
| 247 | #endif |
|---|
| 248 | |
|---|
| 249 | #if 0 |
|---|
| 250 | #define B_DUMP_ENTRY(file) do{unsigned i;for(i=0;i<BFIFO_N_ENTRYS;i++) {BDBG_MSG_IO(file, ("%#x:%u %lld %lld %u", file, i, B_ENTRY(file,i)->voff, B_ENTRY(file,i)->doff, (unsigned)B_ENTRY(file,i)->size));}}while(0) |
|---|
| 251 | #else |
|---|
| 252 | #define B_DUMP_ENTRY(file) |
|---|
| 253 | #endif |
|---|
| 254 | |
|---|
| 255 | |
|---|
| 256 | static ssize_t |
|---|
| 257 | b_read(struct bfile_io_read_posix *fd, void *buf, size_t count) |
|---|
| 258 | { |
|---|
| 259 | return fd->self.read(&fd->self, buf, count); |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | static off_t |
|---|
| 263 | b_rseek(struct bfile_io_read_posix *fd, off_t offset, int whence) |
|---|
| 264 | { |
|---|
| 265 | return fd->self.seek(&fd->self, offset, whence); |
|---|
| 266 | } |
|---|
| 267 | |
|---|
| 268 | static ssize_t |
|---|
| 269 | b_write(struct bfile_io_write_posix *fd, const void *buf, size_t count) |
|---|
| 270 | { |
|---|
| 271 | return fd->self.write(&fd->self, buf, count); |
|---|
| 272 | } |
|---|
| 273 | |
|---|
| 274 | static off_t |
|---|
| 275 | b_wseek(struct bfile_io_write_posix *fd, off_t offset, int whence) |
|---|
| 276 | { |
|---|
| 277 | return bfile_io_write_posix_seek(fd, offset, whence); |
|---|
| 278 | } |
|---|
| 279 | |
|---|
| 280 | static ssize_t |
|---|
| 281 | bpvrfifo_write(bfile_io_write_t fd, const void *buf_, size_t length) |
|---|
| 282 | { |
|---|
| 283 | struct bfile_io_write_fifo *file = (struct bfile_io_write_fifo*) fd; |
|---|
| 284 | ssize_t result; |
|---|
| 285 | const void *buf = buf_; |
|---|
| 286 | unsigned i; |
|---|
| 287 | |
|---|
| 288 | BDBG_ASSERT(file->header); |
|---|
| 289 | BDBG_MSG_IO(file, (">write:%u %lld:%u", file->header->busy, file->offset, (unsigned)length )); |
|---|
| 290 | b_lock(file); |
|---|
| 291 | file->header->busy++; |
|---|
| 292 | for(result=0;length>0;) { |
|---|
| 293 | size_t to_write = length; |
|---|
| 294 | ssize_t rc; |
|---|
| 295 | struct bpvrfifo_entry *entry; |
|---|
| 296 | off_t boundary; |
|---|
| 297 | off_t rc_off; |
|---|
| 298 | |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | for(entry=NULL,i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 302 | if (B_ENTRY_IS_EMPTY(file,i)) { |
|---|
| 303 | break; |
|---|
| 304 | } |
|---|
| 305 | if(B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size == file->offset) { |
|---|
| 306 | entry = B_ENTRY(file, i); |
|---|
| 307 | break; |
|---|
| 308 | } |
|---|
| 309 | } |
|---|
| 310 | if (!entry) { |
|---|
| 311 | BDBG_WRN(("can't write on descriptor %#x:%lld", (unsigned)file,file->offset)); |
|---|
| 312 | result = -1; |
|---|
| 313 | break; |
|---|
| 314 | } |
|---|
| 315 | if (entry[1].doff!=-1) { |
|---|
| 316 | boundary = entry[1].doff; |
|---|
| 317 | } else { |
|---|
| 318 | boundary = file->size; |
|---|
| 319 | } |
|---|
| 320 | if (to_write > boundary - (entry->doff + entry->size)) { |
|---|
| 321 | to_write = boundary - (entry->doff + entry->size); |
|---|
| 322 | } |
|---|
| 323 | if (to_write<=0) { |
|---|
| 324 | break; |
|---|
| 325 | } |
|---|
| 326 | BDBG_MSG_IO(file, (">writing:%#x [%lld/%lld/%lld/%d] (%u/%u/%lld) %#x", entry->voff, entry->doff, boundary, entry-B_ENTRY(file,0), (unsigned)result, (unsigned)to_write, (unsigned)length, file->offset, (unsigned)buf)); |
|---|
| 327 | b_unlock(file); |
|---|
| 328 | rc_off = b_wseek(&file->data, entry->doff + entry->size, SEEK_SET); |
|---|
| 329 | b_lock(file); |
|---|
| 330 | BDBG_MSG_IO(file, ("wseek:%#x %lld -> %lld", entry->doff + entry->size, rc_off)); |
|---|
| 331 | if (rc_off != entry->doff + entry->size) { |
|---|
| 332 | if (result==0) { |
|---|
| 333 | if (rc_off < 0) { |
|---|
| 334 | result = (ssize_t)rc_off; /* propagate error */ |
|---|
| 335 | } else { |
|---|
| 336 | result = -1; |
|---|
| 337 | } |
|---|
| 338 | } |
|---|
| 339 | break; |
|---|
| 340 | } |
|---|
| 341 | b_unlock(file); |
|---|
| 342 | rc = b_write(&file->data, buf, to_write); |
|---|
| 343 | b_lock(file); |
|---|
| 344 | BDBG_MSG_IO(file, ("<writing:%#x [%lld/%lld/%lld/%d] (%u/%u/%lld) %#x->%d", entry->voff, entry->doff, boundary, entry-B_ENTRY(file,0), (unsigned)result, (unsigned)to_write, (unsigned)length, file->offset, (unsigned)buf, (int)rc)); |
|---|
| 345 | if (rc<=0) { |
|---|
| 346 | if (result==0) { |
|---|
| 347 | result = rc; /* propagate error */ |
|---|
| 348 | } |
|---|
| 349 | break; |
|---|
| 350 | } |
|---|
| 351 | BDBG_ASSERT((size_t)rc <= to_write); |
|---|
| 352 | result += rc; |
|---|
| 353 | length -= (size_t) rc; |
|---|
| 354 | buf = (const uint8_t *)buf + rc; |
|---|
| 355 | entry->size = entry->size + rc; |
|---|
| 356 | file->offset = file->offset + rc; |
|---|
| 357 | BDBG_ASSERT(entry->doff+entry->size <= file->size); |
|---|
| 358 | if (entry->doff + entry->size == file->size) { |
|---|
| 359 | entry = B_ENTRY(file, 0); |
|---|
| 360 | /* reached the end of file, now is a time to allocate new chunk */ |
|---|
| 361 | if (entry->doff == file->start) { |
|---|
| 362 | BDBG_MSG(("write overflow")); |
|---|
| 363 | } else { |
|---|
| 364 | BDBG_MSG_IO(file, ("write wraparound")); |
|---|
| 365 | if (entry->doff != -1) { |
|---|
| 366 | BDBG_ASSERT(B_ENTRY(file,BFIFO_N_ENTRYS-1)->doff==-1); |
|---|
| 367 | /* new entry _always_ should go on top, so shift old entrys down, so we could keep entries sorted by the 'doff' field */ |
|---|
| 368 | for(i=BFIFO_N_ENTRYS-1;i>0;i--) { |
|---|
| 369 | *B_ENTRY(file,i) = *B_ENTRY(file, i-1); |
|---|
| 370 | } |
|---|
| 371 | } |
|---|
| 372 | entry->voff = file->offset; |
|---|
| 373 | entry->doff = file->start; |
|---|
| 374 | entry->size = 0; |
|---|
| 375 | } |
|---|
| 376 | } |
|---|
| 377 | } |
|---|
| 378 | file->header->busy--; |
|---|
| 379 | B_DUMP_ENTRY(file); |
|---|
| 380 | BDBG_MSG_IO(file, ("<write:%u %lld:%u -> %d", file->header->busy, file->offset, (unsigned)length, (int)result)); |
|---|
| 381 | if(file->writeSnapshotFile) { |
|---|
| 382 | bfile_fifo_write_snapshot_locked(file->writeSnapshotFile); |
|---|
| 383 | file->writeSnapshotFile = NULL; |
|---|
| 384 | } |
|---|
| 385 | b_unlock(file); |
|---|
| 386 | return result; |
|---|
| 387 | } |
|---|
| 388 | |
|---|
| 389 | #ifdef DIRECT_IO_SUPPORT |
|---|
| 390 | /* we need to maintain data file aligned by 4096 (for DIRECT I/O) and 188 aligned to keep it valid transport packet */ |
|---|
| 391 | /* it rounds in 192K */ |
|---|
| 392 | #define B_DATA_ALIGN ((188/4)*4096) |
|---|
| 393 | #else |
|---|
| 394 | #define B_DATA_ALIGN (188) |
|---|
| 395 | #endif |
|---|
| 396 | |
|---|
| 397 | static ssize_t |
|---|
| 398 | bpvrfifo_read(bfile_io_read_t fd, void *buf_, size_t length) |
|---|
| 399 | { |
|---|
| 400 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo*) fd; |
|---|
| 401 | ssize_t result; |
|---|
| 402 | void *buf = buf_; |
|---|
| 403 | unsigned i; |
|---|
| 404 | ssize_t rc; |
|---|
| 405 | |
|---|
| 406 | |
|---|
| 407 | BDBG_ASSERT(file->header); |
|---|
| 408 | BDBG_MSG_IO(file, (">read:%u %lld:%u", file->header->busy, file->cur_pos, (unsigned)length)); |
|---|
| 409 | b_lock(file); |
|---|
| 410 | file->header->busy++; |
|---|
| 411 | for(result=0;length>0;) { |
|---|
| 412 | off_t rc_off, seek_off; |
|---|
| 413 | size_t to_read = length; |
|---|
| 414 | |
|---|
| 415 | { |
|---|
| 416 | const struct bpvrfifo_entry *entry; /* when lock is released writer could update move entries around, so protect access to the volatile storage */ |
|---|
| 417 | |
|---|
| 418 | |
|---|
| 419 | for(entry=NULL,i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 420 | if (B_ENTRY(file,i)->doff==-1) { |
|---|
| 421 | break; |
|---|
| 422 | } |
|---|
| 423 | if( B_ENTRY(file,i)->voff <= file->cur_pos && |
|---|
| 424 | B_ENTRY(file,i)->voff + B_ENTRY(file, i)->size > file->cur_pos) { |
|---|
| 425 | entry = B_ENTRY(file,i); |
|---|
| 426 | break; |
|---|
| 427 | } |
|---|
| 428 | } |
|---|
| 429 | if (!entry) { |
|---|
| 430 | if (result==0) { |
|---|
| 431 | if (B_ENTRY(file, 0)->voff > file->cur_pos) { |
|---|
| 432 | BDBG_WRN(("out of bounds offset %#x,%lld", (unsigned)file,file->cur_pos)); |
|---|
| 433 | result = -1; |
|---|
| 434 | } |
|---|
| 435 | } |
|---|
| 436 | break; |
|---|
| 437 | } |
|---|
| 438 | if (to_read > entry->size - (file->cur_pos - entry->voff)) { |
|---|
| 439 | to_read = entry->size - (file->cur_pos - entry->voff); |
|---|
| 440 | } |
|---|
| 441 | seek_off = entry->doff + (file->cur_pos - entry->voff); |
|---|
| 442 | BDBG_MSG_IO(file, (">reading: [%lld/%lld/%d -> %lld] (%u/%u/%u/%lld) %#x", entry->voff, entry->doff, entry-B_ENTRY(file,0), seek_off, (unsigned)result, (unsigned)to_read, (unsigned)length, file->cur_pos, (unsigned)buf)); |
|---|
| 443 | } |
|---|
| 444 | b_unlock(file); |
|---|
| 445 | rc_off = b_rseek(&file->data, seek_off, SEEK_SET); |
|---|
| 446 | b_lock(file); |
|---|
| 447 | BDBG_MSG_IO(file, ("rseek: %lld -> %lld", seek_off, rc_off)); |
|---|
| 448 | if (rc_off != seek_off) { |
|---|
| 449 | if (result==0) { |
|---|
| 450 | if (rc_off < 0) { |
|---|
| 451 | result = (ssize_t)rc_off; /* propagate error */ |
|---|
| 452 | } else { |
|---|
| 453 | /* coverity[use] */ |
|---|
| 454 | BDBG_WRN(("bpvrfifo_read: %#lx can't seek to %lld(instead %lld)", (unsigned long)file, seek_off, rc_off)); |
|---|
| 455 | result = -1; |
|---|
| 456 | } |
|---|
| 457 | } |
|---|
| 458 | break; |
|---|
| 459 | } |
|---|
| 460 | b_unlock(file); |
|---|
| 461 | rc = b_read(&file->data, buf, to_read); |
|---|
| 462 | b_lock(file); |
|---|
| 463 | BDBG_MSG_IO(file, ("<reading: %lld (%u/%u/%u/%lld) %#x->%d", seek_off, (unsigned)result, (unsigned)to_read, (unsigned)length, file->cur_pos, (unsigned)buf, (int)rc)); |
|---|
| 464 | if (rc!=(ssize_t)to_read) { |
|---|
| 465 | if (result==0) { |
|---|
| 466 | result = rc; /* propagate error */ |
|---|
| 467 | } |
|---|
| 468 | break; |
|---|
| 469 | } |
|---|
| 470 | BDBG_ASSERT((size_t)rc <= to_read); |
|---|
| 471 | result += rc; |
|---|
| 472 | buf = (uint8_t *)buf + rc; |
|---|
| 473 | length -= (size_t) rc; |
|---|
| 474 | file->cur_pos = file->cur_pos + rc; |
|---|
| 475 | } |
|---|
| 476 | file->header->busy--; |
|---|
| 477 | B_DUMP_ENTRY(file); |
|---|
| 478 | BDBG_MSG_IO(file, ("<read:%u %lld:%u=%d", file->header->busy, file->cur_pos, (unsigned)length, (int)result)); |
|---|
| 479 | |
|---|
| 480 | b_unlock(file); |
|---|
| 481 | return result; |
|---|
| 482 | } |
|---|
| 483 | |
|---|
| 484 | |
|---|
| 485 | static int |
|---|
| 486 | bpvrfifo_bounds_locked(const struct bfile_io_read_fifo *file, off_t *first, off_t *last) |
|---|
| 487 | { |
|---|
| 488 | unsigned i; |
|---|
| 489 | |
|---|
| 490 | BDBG_ASSERT(file->header); |
|---|
| 491 | |
|---|
| 492 | if (B_ENTRY_IS_EMPTY(file,0)) { |
|---|
| 493 | *first = *last = 0; |
|---|
| 494 | } else { |
|---|
| 495 | *first = B_ENTRY(file,0)->voff; |
|---|
| 496 | *last = B_ENTRY(file,0)->voff + B_ENTRY(file,0)->size; |
|---|
| 497 | } |
|---|
| 498 | |
|---|
| 499 | for(i=1;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 500 | if (B_ENTRY_IS_EMPTY(file,i)) { |
|---|
| 501 | break; |
|---|
| 502 | } |
|---|
| 503 | if(B_ENTRY(file,i)->voff >= *last) { |
|---|
| 504 | *last = B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size; |
|---|
| 505 | } |
|---|
| 506 | if(B_ENTRY(file,i)->voff < *first) { |
|---|
| 507 | *first = B_ENTRY(file,i)->voff; |
|---|
| 508 | } |
|---|
| 509 | } |
|---|
| 510 | |
|---|
| 511 | if( file->header->trim_gap ) { |
|---|
| 512 | *first += (off_t)(file->header->trim_gap); |
|---|
| 513 | } |
|---|
| 514 | |
|---|
| 515 | |
|---|
| 516 | return 0; |
|---|
| 517 | } |
|---|
| 518 | |
|---|
| 519 | static int |
|---|
| 520 | bpvrfifo_bounds(bfile_io_read_t fd, off_t *first, off_t *last ) |
|---|
| 521 | { |
|---|
| 522 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *) fd; |
|---|
| 523 | int rc; |
|---|
| 524 | |
|---|
| 525 | BDBG_ASSERT(file->header); |
|---|
| 526 | b_lock(file); /* don't need to set busy because lock isn't released */ |
|---|
| 527 | |
|---|
| 528 | BDBG_MSG_IO(file, (">bounds")); |
|---|
| 529 | rc = bpvrfifo_bounds_locked(file, first, last); |
|---|
| 530 | BDBG_MSG_IO(file, ("<bounds: %lld..%lld", *first, *last)); |
|---|
| 531 | b_unlock(file); |
|---|
| 532 | return rc; |
|---|
| 533 | } |
|---|
| 534 | |
|---|
| 535 | static off_t |
|---|
| 536 | bpvrfifo_trim(bfile_io_write_t fd, off_t trim_pos) |
|---|
| 537 | { |
|---|
| 538 | struct bfile_io_write_fifo *file = (struct bfile_io_write_fifo *) fd; |
|---|
| 539 | off_t result; |
|---|
| 540 | off_t min_voff = 0; |
|---|
| 541 | unsigned i,j; |
|---|
| 542 | |
|---|
| 543 | BDBG_ASSERT(file->header); |
|---|
| 544 | b_lock(file); |
|---|
| 545 | BDBG_MSG_IO(file, (">trim:%u %lld", file->header->busy, trim_pos)); |
|---|
| 546 | result = 0; |
|---|
| 547 | if (file->header->busy) { |
|---|
| 548 | goto done; |
|---|
| 549 | } |
|---|
| 550 | |
|---|
| 551 | /* trim_pos = (trim_pos) & (~(4096-1)); */ |
|---|
| 552 | if (trim_pos>file->offset) { |
|---|
| 553 | trim_pos = file->offset; |
|---|
| 554 | } else if (trim_pos<0) { |
|---|
| 555 | trim_pos = 0; |
|---|
| 556 | } |
|---|
| 557 | |
|---|
| 558 | for(i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 559 | if (B_ENTRY_IS_EMPTY(file,i)) { |
|---|
| 560 | break; |
|---|
| 561 | } else if( B_ENTRY(file,i)->voff >= trim_pos) { |
|---|
| 562 | if (min_voff==0 || min_voff > B_ENTRY(file,i)->voff) |
|---|
| 563 | min_voff = B_ENTRY(file,i)->voff; |
|---|
| 564 | continue; |
|---|
| 565 | } else if (B_ENTRY(file, i)->voff + B_ENTRY(file,i)->size > trim_pos ) { |
|---|
| 566 | B_ENTRY(file, i)->size -= trim_pos - B_ENTRY(file,i)->voff; |
|---|
| 567 | B_ENTRY(file, i)->doff += trim_pos - B_ENTRY(file,i)->voff; |
|---|
| 568 | B_ENTRY(file, i)->voff = trim_pos; |
|---|
| 569 | result = trim_pos; |
|---|
| 570 | } else { |
|---|
| 571 | if (result < B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size) { |
|---|
| 572 | result = B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size; |
|---|
| 573 | } |
|---|
| 574 | B_ENTRY_CLEAR(file,i); /* mark entry as unused */ |
|---|
| 575 | } |
|---|
| 576 | } |
|---|
| 577 | if (!result && trim_pos <= min_voff) |
|---|
| 578 | result = min_voff; |
|---|
| 579 | /* collapse empty entries */ |
|---|
| 580 | for(i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 581 | if (B_ENTRY_IS_EMPTY(file,i)) { |
|---|
| 582 | for(j=i+1;j<BFIFO_N_ENTRYS;j++) { |
|---|
| 583 | if (!B_ENTRY_IS_EMPTY(file,j)) { |
|---|
| 584 | *B_ENTRY(file, i) = *B_ENTRY(file, j); |
|---|
| 585 | B_ENTRY_CLEAR(file, j); |
|---|
| 586 | break; |
|---|
| 587 | } |
|---|
| 588 | } |
|---|
| 589 | if (j==BFIFO_N_ENTRYS) { |
|---|
| 590 | break; |
|---|
| 591 | } |
|---|
| 592 | } |
|---|
| 593 | } |
|---|
| 594 | if (B_ENTRY_IS_EMPTY(file,0)) { |
|---|
| 595 | /* file was trimed to bones, create new entry */ |
|---|
| 596 | B_ENTRY(file, 0)->doff = file->start; |
|---|
| 597 | B_ENTRY(file, 0)->voff = result; |
|---|
| 598 | B_ENTRY(file, 0)->size = 0; |
|---|
| 599 | } |
|---|
| 600 | done: |
|---|
| 601 | B_DUMP_ENTRY(file); |
|---|
| 602 | BDBG_MSG_IO(file, ("<trim:%u %lld", file->header->busy, result)); |
|---|
| 603 | b_unlock(file); |
|---|
| 604 | return result; |
|---|
| 605 | } |
|---|
| 606 | |
|---|
| 607 | static off_t |
|---|
| 608 | bpvrfifo_seek(bfile_io_read_t fd, off_t offset, int whence) |
|---|
| 609 | { |
|---|
| 610 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *) fd; |
|---|
| 611 | off_t size,begin; |
|---|
| 612 | int rc; |
|---|
| 613 | |
|---|
| 614 | BDBG_MSG_IO(file,(">seek: %lld %d", offset, whence)); |
|---|
| 615 | b_lock(file); |
|---|
| 616 | |
|---|
| 617 | if (whence==SEEK_CUR && offset==0) { |
|---|
| 618 | /* special case, which is used to rerrieve current position, without bound checking */ |
|---|
| 619 | offset = file->cur_pos; |
|---|
| 620 | goto done; |
|---|
| 621 | } |
|---|
| 622 | rc = bpvrfifo_bounds_locked(file, &begin, &size); |
|---|
| 623 | if (rc<0) { |
|---|
| 624 | offset = -1; |
|---|
| 625 | goto error; |
|---|
| 626 | } |
|---|
| 627 | /* locate where file begins */ |
|---|
| 628 | switch(whence) { |
|---|
| 629 | case SEEK_CUR: |
|---|
| 630 | offset = file->cur_pos + offset; |
|---|
| 631 | break; |
|---|
| 632 | case SEEK_END: |
|---|
| 633 | offset = size + offset; |
|---|
| 634 | break; |
|---|
| 635 | case SEEK_SET: |
|---|
| 636 | break; |
|---|
| 637 | default: |
|---|
| 638 | BDBG_ERR(("unknown seek whence %d", whence)); |
|---|
| 639 | goto error; |
|---|
| 640 | } |
|---|
| 641 | if (offset == file->cur_pos) { |
|---|
| 642 | goto done; |
|---|
| 643 | } |
|---|
| 644 | if (offset < 0 || offset >= size) { |
|---|
| 645 | BDBG_WRN(("<seek out out bounds 0..%lld..%lld", offset, size)); |
|---|
| 646 | offset = -1; |
|---|
| 647 | goto error; |
|---|
| 648 | } |
|---|
| 649 | if (offset < begin) { |
|---|
| 650 | offset = begin; |
|---|
| 651 | } |
|---|
| 652 | |
|---|
| 653 | /* just assign new offset */ |
|---|
| 654 | done: |
|---|
| 655 | file->cur_pos = offset; |
|---|
| 656 | error: |
|---|
| 657 | BDBG_MSG_IO(file, ("<seek: %lld", offset)); |
|---|
| 658 | b_unlock(file); |
|---|
| 659 | return offset; |
|---|
| 660 | } |
|---|
| 661 | |
|---|
| 662 | static const struct bfile_io_write bpvrfifo_io_write = { |
|---|
| 663 | bpvrfifo_write, |
|---|
| 664 | bpvrfifo_trim, |
|---|
| 665 | BIO_DEFAULT_PRIORITY |
|---|
| 666 | }; |
|---|
| 667 | |
|---|
| 668 | static const struct bfile_io_read bpvrfifo_io_read = { |
|---|
| 669 | bpvrfifo_read, |
|---|
| 670 | bpvrfifo_seek, |
|---|
| 671 | bpvrfifo_bounds, |
|---|
| 672 | BIO_DEFAULT_PRIORITY |
|---|
| 673 | }; |
|---|
| 674 | |
|---|
| 675 | static struct bfile_io_write_fifo * |
|---|
| 676 | bpvrfifo_write_open(const char *fname, bool direct, off_t start ) |
|---|
| 677 | { |
|---|
| 678 | struct bfile_io_write_fifo *file = BKNI_Malloc(sizeof(*file)); |
|---|
| 679 | BERR_Code rc; |
|---|
| 680 | unsigned i; |
|---|
| 681 | |
|---|
| 682 | if (!file) { |
|---|
| 683 | rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); |
|---|
| 684 | goto err_alloc; |
|---|
| 685 | } |
|---|
| 686 | BKNI_Memset(file, 0, sizeof(*file)); |
|---|
| 687 | file->header = &file->_header; |
|---|
| 688 | file->header->data.h.signature = bpvrfifo_signature; |
|---|
| 689 | file->writeSnapshotFile = NULL; |
|---|
| 690 | rc = BKNI_CreateMutex(&file->header->lock); |
|---|
| 691 | if (rc!=BERR_SUCCESS) { |
|---|
| 692 | goto err_lock; |
|---|
| 693 | } |
|---|
| 694 | |
|---|
| 695 | rc = bfile_io_write_posix_open(&file->data, fname, direct); |
|---|
| 696 | if(rc!=NEXUS_SUCCESS) { rc = BERR_TRACE(rc); goto err_open_data; } |
|---|
| 697 | /* initialize data */ |
|---|
| 698 | file->self = bpvrfifo_io_write; |
|---|
| 699 | file->start = start; |
|---|
| 700 | file->ref_cnt = 1; |
|---|
| 701 | file->size = 512 * 1024; |
|---|
| 702 | for(i=0;i<BFIFO_N_ENTRYS;i++) { |
|---|
| 703 | B_ENTRY_CLEAR(file, i); |
|---|
| 704 | } |
|---|
| 705 | B_ENTRY(file, 0)->doff = file->start; |
|---|
| 706 | return file; |
|---|
| 707 | |
|---|
| 708 | err_open_data: |
|---|
| 709 | BKNI_DestroyMutex(file->header->lock); |
|---|
| 710 | err_lock: |
|---|
| 711 | BKNI_Free(file); |
|---|
| 712 | err_alloc: |
|---|
| 713 | return NULL; |
|---|
| 714 | } |
|---|
| 715 | |
|---|
| 716 | static bfile_io_write_t |
|---|
| 717 | bpvrfifo_write_file(struct bfile_io_write_fifo *file) |
|---|
| 718 | { |
|---|
| 719 | return &file->self; |
|---|
| 720 | } |
|---|
| 721 | |
|---|
| 722 | /* decrement reference counter and once it reaches 0 then release memory */ |
|---|
| 723 | static void |
|---|
| 724 | bpvrfifo_write_release(struct bfile_io_write_fifo *file) |
|---|
| 725 | { |
|---|
| 726 | bool last; |
|---|
| 727 | |
|---|
| 728 | b_lock(file); |
|---|
| 729 | BDBG_ASSERT(file->header); |
|---|
| 730 | BDBG_MSG_IO(file, ("release:%u:%u", file->ref_cnt, file->header->busy)); |
|---|
| 731 | BDBG_ASSERT(file->ref_cnt); |
|---|
| 732 | file->ref_cnt--; |
|---|
| 733 | last = file->ref_cnt==0; |
|---|
| 734 | BDBG_ASSERT(!last || file->header->busy==0); |
|---|
| 735 | b_unlock(file); |
|---|
| 736 | if (last) { |
|---|
| 737 | BKNI_DestroyMutex(file->header->lock); |
|---|
| 738 | BKNI_Free(file); |
|---|
| 739 | } |
|---|
| 740 | return; |
|---|
| 741 | } |
|---|
| 742 | |
|---|
| 743 | static void |
|---|
| 744 | bpvrfifo_write_close(struct bfile_io_write_fifo *file) |
|---|
| 745 | { |
|---|
| 746 | bfile_io_write_posix_close(&file->data); |
|---|
| 747 | bpvrfifo_write_release(file); |
|---|
| 748 | return; |
|---|
| 749 | } |
|---|
| 750 | |
|---|
| 751 | static struct bfile_io_read_fifo * |
|---|
| 752 | bpvrfifo_read_open(const char *fname, bool direct, struct bfile_io_write_fifo *writer) |
|---|
| 753 | { |
|---|
| 754 | struct bfile_io_read_fifo *file = BKNI_Malloc(sizeof(*file)); |
|---|
| 755 | NEXUS_Error rc; |
|---|
| 756 | |
|---|
| 757 | if (!file) { |
|---|
| 758 | rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); |
|---|
| 759 | goto err_alloc; |
|---|
| 760 | } |
|---|
| 761 | rc = bfile_io_read_posix_open(&file->data, fname, direct); |
|---|
| 762 | if (rc!=NEXUS_SUCCESS) { rc = BERR_TRACE(rc); goto err_open_data; } |
|---|
| 763 | file->writer = writer; |
|---|
| 764 | file->self = bpvrfifo_io_read; |
|---|
| 765 | if (writer) { |
|---|
| 766 | file->header = writer->header; |
|---|
| 767 | b_lock(file); |
|---|
| 768 | file->writer->ref_cnt++; |
|---|
| 769 | b_unlock(file); |
|---|
| 770 | } else { |
|---|
| 771 | BERR_Code rc; |
|---|
| 772 | |
|---|
| 773 | file->header = BKNI_Malloc(sizeof(*file->header)); |
|---|
| 774 | BKNI_Memset(file->header, 0, sizeof(*file->header)); |
|---|
| 775 | file->header->data.h.signature = bpvrfifo_signature; |
|---|
| 776 | rc = BKNI_CreateMutex(&file->header->lock); |
|---|
| 777 | if (rc!=BERR_SUCCESS) { |
|---|
| 778 | goto err_lock; |
|---|
| 779 | } |
|---|
| 780 | } |
|---|
| 781 | return file; |
|---|
| 782 | |
|---|
| 783 | err_lock: |
|---|
| 784 | bfile_io_read_posix_close(&file->data); |
|---|
| 785 | err_open_data: |
|---|
| 786 | BKNI_Free(file); |
|---|
| 787 | err_alloc: |
|---|
| 788 | return NULL; |
|---|
| 789 | } |
|---|
| 790 | |
|---|
| 791 | static bfile_io_read_t |
|---|
| 792 | bpvrfifo_read_file(struct bfile_io_read_fifo *file) |
|---|
| 793 | { |
|---|
| 794 | return &file->self; |
|---|
| 795 | } |
|---|
| 796 | |
|---|
| 797 | |
|---|
| 798 | static void |
|---|
| 799 | bpvrfifo_read_close(struct bfile_io_read_fifo *file) |
|---|
| 800 | { |
|---|
| 801 | bfile_io_read_posix_close(&file->data); |
|---|
| 802 | if(file->writer) { |
|---|
| 803 | bpvrfifo_write_release(file->writer); |
|---|
| 804 | } else { |
|---|
| 805 | BKNI_DestroyMutex(file->header->lock); |
|---|
| 806 | BKNI_Free(file->header); |
|---|
| 807 | } |
|---|
| 808 | BKNI_Free(file); |
|---|
| 809 | return; |
|---|
| 810 | } |
|---|
| 811 | |
|---|
| 812 | #define B_TRIM_TIMER 5000 |
|---|
| 813 | #define B_TRIM_TRY_TIMER 30 |
|---|
| 814 | |
|---|
| 815 | struct bfile_out_desc { |
|---|
| 816 | struct bfile_io_write_fifo *file; |
|---|
| 817 | unsigned trim_count; |
|---|
| 818 | off_t trim_off; |
|---|
| 819 | }; |
|---|
| 820 | |
|---|
| 821 | struct NEXUS_FifoRecord { |
|---|
| 822 | struct NEXUS_FileRecord self; |
|---|
| 823 | struct bfile_out_desc data; |
|---|
| 824 | struct bfile_out_desc index; |
|---|
| 825 | struct bfile_io_read_fifo *rd_index; |
|---|
| 826 | unsigned index_entrysize; |
|---|
| 827 | BNAV_Player_Handle bcm_player; |
|---|
| 828 | NEXUS_TimerHandle timer; /* currently active timer or NULL */ |
|---|
| 829 | NEXUS_Time lastSnapshotTime; |
|---|
| 830 | NEXUS_FifoRecordSettings cfg; |
|---|
| 831 | }; |
|---|
| 832 | |
|---|
| 833 | struct bfile_in_fifo { |
|---|
| 834 | struct NEXUS_FilePlay self; |
|---|
| 835 | struct bfile_io_read_fifo *data; |
|---|
| 836 | struct bfile_io_read_fifo *index; |
|---|
| 837 | struct NEXUS_FifoRecord *writer; |
|---|
| 838 | }; |
|---|
| 839 | |
|---|
| 840 | #define GET_INDEX_FILEIO(fp) (&((NEXUS_FifoRecordHandle) fp)->rd_index->self) |
|---|
| 841 | |
|---|
| 842 | static long |
|---|
| 843 | bp_read(void *buffer, long size, long count, void *fp ) |
|---|
| 844 | { |
|---|
| 845 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 846 | |
|---|
| 847 | return (long)f->read(f, buffer, (size_t)(count*size)); |
|---|
| 848 | } |
|---|
| 849 | |
|---|
| 850 | static long |
|---|
| 851 | bp_tell( void *fp ) |
|---|
| 852 | { |
|---|
| 853 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 854 | return (long)f->seek(f, 0, SEEK_CUR); |
|---|
| 855 | } |
|---|
| 856 | |
|---|
| 857 | #if 0 |
|---|
| 858 | static int |
|---|
| 859 | bp_seek( void *fp, long offset, int origin ) |
|---|
| 860 | { |
|---|
| 861 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 862 | off_t rc; |
|---|
| 863 | rc = f->seek(f, (off_t)offset, origin); |
|---|
| 864 | if ( rc == (off_t)-1) { |
|---|
| 865 | return -1; |
|---|
| 866 | } |
|---|
| 867 | return 0; |
|---|
| 868 | } |
|---|
| 869 | #endif |
|---|
| 870 | |
|---|
| 871 | static int |
|---|
| 872 | bp_bounds(BNAV_Player_Handle handle, void *fp, long *firstIndex, long *lastIndex) |
|---|
| 873 | { |
|---|
| 874 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 875 | off_t first, last; |
|---|
| 876 | unsigned index_entrysize =((NEXUS_FifoRecordHandle)fp)->index_entrysize; |
|---|
| 877 | |
|---|
| 878 | f->bounds(f, &first, &last); |
|---|
| 879 | |
|---|
| 880 | BSTD_UNUSED(handle); |
|---|
| 881 | *firstIndex = first/index_entrysize; |
|---|
| 882 | *lastIndex = (last-1)/index_entrysize; |
|---|
| 883 | |
|---|
| 884 | return 0; |
|---|
| 885 | } |
|---|
| 886 | |
|---|
| 887 | static int |
|---|
| 888 | trim_bp_bounds( BNAV_Player_Handle handle, void *fp, long *firstIndex, long *lastIndex ) |
|---|
| 889 | { |
|---|
| 890 | bfile_io_read_t fd = GET_INDEX_FILEIO(fp); |
|---|
| 891 | off_t first, last; |
|---|
| 892 | unsigned index_entrysize =((NEXUS_FifoRecordHandle)fp)->index_entrysize; |
|---|
| 893 | int rc; |
|---|
| 894 | |
|---|
| 895 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *)fd; |
|---|
| 896 | BDBG_ASSERT(file->header); |
|---|
| 897 | b_lock(file); |
|---|
| 898 | rc = bpvrfifo_bounds_locked(file, &first, &last ); |
|---|
| 899 | if( file->header->trim_gap ) { |
|---|
| 900 | /* Untrimmed file start is first offset minus trim gap */ |
|---|
| 901 | first -= (off_t)(file->header->trim_gap); |
|---|
| 902 | } |
|---|
| 903 | b_unlock(file); |
|---|
| 904 | |
|---|
| 905 | |
|---|
| 906 | BSTD_UNUSED(handle); |
|---|
| 907 | *firstIndex = first/index_entrysize; |
|---|
| 908 | *lastIndex = (last-1)/index_entrysize; |
|---|
| 909 | |
|---|
| 910 | return 0; |
|---|
| 911 | } |
|---|
| 912 | |
|---|
| 913 | static int |
|---|
| 914 | trim_bp_seek( void *fp, long offset, int origin ) |
|---|
| 915 | { |
|---|
| 916 | bfile_io_read_t f = GET_INDEX_FILEIO(fp); |
|---|
| 917 | unsigned index_entrysize =((NEXUS_FifoRecordHandle)fp)->index_entrysize; |
|---|
| 918 | long saveOffset = 0; |
|---|
| 919 | struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *)f; |
|---|
| 920 | off_t rc; |
|---|
| 921 | |
|---|
| 922 | if( file->header->trim_gap ) { |
|---|
| 923 | BNAV_Player_Handle dummyHandle = NULL; |
|---|
| 924 | long firstIdx, lastIdx; |
|---|
| 925 | |
|---|
| 926 | /* Find beginning trimmed area */ |
|---|
| 927 | trim_bp_bounds( dummyHandle, fp, &firstIdx, &lastIdx ); |
|---|
| 928 | saveOffset = firstIdx*index_entrysize; |
|---|
| 929 | |
|---|
| 930 | if( offset && offset < firstIdx*(int)index_entrysize ) { |
|---|
| 931 | /* But don't adjust for a tell request ( offset=0 , origin=SEEK_SET ) */ |
|---|
| 932 | offset = firstIdx*index_entrysize; |
|---|
| 933 | } |
|---|
| 934 | } |
|---|
| 935 | |
|---|
| 936 | rc = f->seek(f, (off_t)offset, origin); |
|---|
| 937 | if ( rc == (off_t)-1) { |
|---|
| 938 | return -1; |
|---|
| 939 | } |
|---|
| 940 | |
|---|
| 941 | |
|---|
| 942 | if ( offset==0 && saveOffset ) { |
|---|
| 943 | /* Fix up cur_pos to actual trim area beginning */ |
|---|
| 944 | b_lock(file); |
|---|
| 945 | file->cur_pos = saveOffset; |
|---|
| 946 | b_unlock(file); |
|---|
| 947 | } |
|---|
| 948 | else if ( offset < file->cur_pos ) { |
|---|
| 949 | /* If get in here , it means trimming is happening */ |
|---|
| 950 | b_lock(file); |
|---|
| 951 | file->cur_pos = offset; |
|---|
| 952 | b_unlock(file); |
|---|
| 953 | } |
|---|
| 954 | |
|---|
| 955 | return 0; |
|---|
| 956 | } |
|---|
| 957 | |
|---|
| 958 | |
|---|
| 959 | static void |
|---|
| 960 | bfile_fifo_close_in(NEXUS_FilePlayHandle f) |
|---|
| 961 | { |
|---|
| 962 | struct bfile_in_fifo *file = (struct bfile_in_fifo *)f; |
|---|
| 963 | |
|---|
| 964 | BDBG_ASSERT(file->data); |
|---|
| 965 | BDBG_ASSERT(file->index); |
|---|
| 966 | bpvrfifo_read_close(file->data); |
|---|
| 967 | bpvrfifo_read_close(file->index); |
|---|
| 968 | BKNI_Free(file); |
|---|
| 969 | return; |
|---|
| 970 | } |
|---|
| 971 | |
|---|
| 972 | NEXUS_FilePlayHandle |
|---|
| 973 | NEXUS_FifoPlay_Open(const char *fname, const char *indexname, NEXUS_FifoRecordHandle writer) |
|---|
| 974 | { |
|---|
| 975 | struct bfile_in_fifo *file; |
|---|
| 976 | NEXUS_Error rc; |
|---|
| 977 | |
|---|
| 978 | if (fname==NULL) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; } |
|---|
| 979 | if (indexname==NULL) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; } |
|---|
| 980 | |
|---|
| 981 | file = BKNI_Malloc(sizeof(*file)); |
|---|
| 982 | if (!file) { rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); goto err_alloc; } |
|---|
| 983 | BKNI_Memset(file, 0, sizeof(*file)); |
|---|
| 984 | |
|---|
| 985 | file->data = bpvrfifo_read_open(fname, true, writer?writer->data.file:NULL); |
|---|
| 986 | if (!file->data) { goto err_data;} |
|---|
| 987 | |
|---|
| 988 | file->index = bpvrfifo_read_open(indexname, false, writer?writer->index.file:NULL); |
|---|
| 989 | if (!file->index) { goto err_index;} |
|---|
| 990 | |
|---|
| 991 | if (writer==NULL) { |
|---|
| 992 | struct bpvrfifo_header *buf; |
|---|
| 993 | ssize_t rc; |
|---|
| 994 | |
|---|
| 995 | buf = file->index->header; |
|---|
| 996 | b_rseek(&file->index->data, 0, SEEK_SET); |
|---|
| 997 | rc = b_read(&file->index->data, &buf->data, sizeof(buf->data)); |
|---|
| 998 | if (rc!=sizeof(buf->data) || buf->data.h.signature.signature[0]!=bpvrfifo_signature.signature[0]) { |
|---|
| 999 | rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1000 | goto err_meta; |
|---|
| 1001 | } |
|---|
| 1002 | |
|---|
| 1003 | buf = file->data->header; |
|---|
| 1004 | b_rseek(&file->index->data, sizeof(buf->data), SEEK_SET); |
|---|
| 1005 | rc = b_read(&file->index->data, buf, sizeof(buf->data)); |
|---|
| 1006 | if (rc!=sizeof(buf->data) || buf->data.h.signature.signature[0]!=bpvrfifo_signature.signature[0]) { |
|---|
| 1007 | rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1008 | goto err_meta; |
|---|
| 1009 | } |
|---|
| 1010 | } |
|---|
| 1011 | |
|---|
| 1012 | file->self.file.index = bpvrfifo_read_file(file->index); |
|---|
| 1013 | file->self.file.data = bpvrfifo_read_file(file->data); |
|---|
| 1014 | |
|---|
| 1015 | file->self.file.close = bfile_fifo_close_in; |
|---|
| 1016 | |
|---|
| 1017 | return &file->self; |
|---|
| 1018 | |
|---|
| 1019 | err_meta: |
|---|
| 1020 | bpvrfifo_read_close(file->index); |
|---|
| 1021 | err_index: |
|---|
| 1022 | bpvrfifo_read_close(file->data); |
|---|
| 1023 | err_data: |
|---|
| 1024 | BKNI_Free(file); |
|---|
| 1025 | err_alloc: |
|---|
| 1026 | return NULL; |
|---|
| 1027 | } |
|---|
| 1028 | |
|---|
| 1029 | |
|---|
| 1030 | static void |
|---|
| 1031 | bfile_fifo_write_snapshot_locked(struct NEXUS_FifoRecord *file) |
|---|
| 1032 | { |
|---|
| 1033 | const struct bpvrfifo_header *buf; |
|---|
| 1034 | |
|---|
| 1035 | buf = file->index.file->header; |
|---|
| 1036 | b_wseek(&file->index.file->data, 0, SEEK_SET); |
|---|
| 1037 | b_write(&file->index.file->data, &buf->data, sizeof(buf->data)); |
|---|
| 1038 | |
|---|
| 1039 | buf = file->data.file->header; |
|---|
| 1040 | b_wseek(&file->index.file->data, sizeof(buf->data), SEEK_SET); |
|---|
| 1041 | b_write(&file->index.file->data, &buf->data, sizeof(buf->data)); |
|---|
| 1042 | return; |
|---|
| 1043 | } |
|---|
| 1044 | |
|---|
| 1045 | static void |
|---|
| 1046 | bfile_fifo_close_out(NEXUS_FileRecordHandle f) |
|---|
| 1047 | { |
|---|
| 1048 | struct NEXUS_FifoRecord *file = (struct NEXUS_FifoRecord *)f; |
|---|
| 1049 | |
|---|
| 1050 | if (file->timer) { |
|---|
| 1051 | NEXUS_CancelTimer(file->timer); |
|---|
| 1052 | } |
|---|
| 1053 | if (file->bcm_player) { |
|---|
| 1054 | BNAV_Player_Close(file->bcm_player); |
|---|
| 1055 | } |
|---|
| 1056 | b_lock(file->index.file); |
|---|
| 1057 | bfile_fifo_write_snapshot_locked(file); |
|---|
| 1058 | bfile_fifo_write_snapshot_locked(file); |
|---|
| 1059 | b_unlock(file->index.file); |
|---|
| 1060 | |
|---|
| 1061 | |
|---|
| 1062 | bpvrfifo_read_close(file->rd_index); |
|---|
| 1063 | bpvrfifo_write_close(file->data.file); |
|---|
| 1064 | bpvrfifo_write_close(file->index.file); |
|---|
| 1065 | BKNI_Free(file); |
|---|
| 1066 | return; |
|---|
| 1067 | } |
|---|
| 1068 | |
|---|
| 1069 | static void |
|---|
| 1070 | b_trim_try_player(NEXUS_FifoRecordHandle file) |
|---|
| 1071 | { |
|---|
| 1072 | if (file->bcm_player==NULL) { |
|---|
| 1073 | BNAV_DecoderFeatures features = {1,1,1,1}; |
|---|
| 1074 | BNAV_Player_Settings cfg; |
|---|
| 1075 | |
|---|
| 1076 | BNAV_Player_GetDefaultSettings(&cfg); |
|---|
| 1077 | |
|---|
| 1078 | cfg.videoPid = 0x1FFF; /* since BNAV_Player doesn't like 0 */ |
|---|
| 1079 | cfg.filePointer = file; |
|---|
| 1080 | cfg.normalPlayBufferSize = 1024*128; |
|---|
| 1081 | cfg.decoderFeatures = features; |
|---|
| 1082 | cfg.readCb = bp_read; |
|---|
| 1083 | cfg.tellCb = bp_tell; |
|---|
| 1084 | cfg.seekCb = trim_bp_seek; |
|---|
| 1085 | cfg.boundsCb = trim_bp_bounds; |
|---|
| 1086 | cfg.transportTimestampEnabled = false; |
|---|
| 1087 | if (BNAV_Player_Open(&file->bcm_player, &cfg)!=0) { |
|---|
| 1088 | return; |
|---|
| 1089 | } |
|---|
| 1090 | BNAV_Player_GetSettings(file->bcm_player, &cfg); |
|---|
| 1091 | file->index_entrysize = BNAV_GetEntrySize(cfg.navVersion); |
|---|
| 1092 | } |
|---|
| 1093 | return; |
|---|
| 1094 | } |
|---|
| 1095 | |
|---|
| 1096 | /* this functions return true if trim was successfull and false otherwise */ |
|---|
| 1097 | static bool |
|---|
| 1098 | b_try_trim_file(struct bfile_out_desc *desc) |
|---|
| 1099 | { |
|---|
| 1100 | off_t rc; |
|---|
| 1101 | |
|---|
| 1102 | if (desc->trim_count==0) { |
|---|
| 1103 | return true; |
|---|
| 1104 | } |
|---|
| 1105 | if (desc->trim_off>0) { |
|---|
| 1106 | BDBG_MSG((">try_trim %#x:%u %lld", (unsigned)desc->file, desc->trim_count, desc->trim_off)); |
|---|
| 1107 | rc = desc->file->self.trim(&desc->file->self, desc->trim_off); |
|---|
| 1108 | BDBG_MSG(("<try_trim %#x:%u %lld:%lld", (unsigned)desc->file, desc->trim_count, desc->trim_off, rc)); |
|---|
| 1109 | if (rc == 0) { |
|---|
| 1110 | desc->trim_count++; |
|---|
| 1111 | return false; |
|---|
| 1112 | } |
|---|
| 1113 | if (rc<0) { |
|---|
| 1114 | BDBG_WRN(("trim has failed")); |
|---|
| 1115 | return true; |
|---|
| 1116 | } |
|---|
| 1117 | } |
|---|
| 1118 | desc->trim_count = 0; |
|---|
| 1119 | return true; |
|---|
| 1120 | } |
|---|
| 1121 | |
|---|
| 1122 | #define B_GET_OFF_T(p) ((p)->offsetLo|(((uint64_t)(p)->offsetHi)<<32)) |
|---|
| 1123 | |
|---|
| 1124 | /* this function called from the timer context */ |
|---|
| 1125 | static void |
|---|
| 1126 | b_trim_timer(void *file_) |
|---|
| 1127 | { |
|---|
| 1128 | NEXUS_FifoRecordHandle file = file_; |
|---|
| 1129 | unsigned timeout = B_TRIM_TIMER; |
|---|
| 1130 | long firstIndex, lastIndex; |
|---|
| 1131 | BNAV_Player_Position first, last; |
|---|
| 1132 | int rc; |
|---|
| 1133 | unsigned long interval; |
|---|
| 1134 | NEXUS_Time start, stop; |
|---|
| 1135 | |
|---|
| 1136 | NEXUS_Time_Get(&start); |
|---|
| 1137 | if(file->cfg.snapshotInterval != 0 && (NEXUS_Time_Diff(&start, &file->lastSnapshotTime)/1000)>=(long)file->cfg.snapshotInterval) { |
|---|
| 1138 | b_lock(file->index.file); |
|---|
| 1139 | file->index.file->writeSnapshotFile = file; /* we can't write data right there since it could overlap with running write operation and would corrupt the file write pointer */ |
|---|
| 1140 | b_unlock(file->index.file); |
|---|
| 1141 | file->lastSnapshotTime = start; |
|---|
| 1142 | } |
|---|
| 1143 | |
|---|
| 1144 | if (file->index.trim_count || file->data.trim_count) { |
|---|
| 1145 | /* trim index first */ |
|---|
| 1146 | if (!b_try_trim_file(&file->index)) { |
|---|
| 1147 | timeout = B_TRIM_TRY_TIMER; |
|---|
| 1148 | goto done; |
|---|
| 1149 | } |
|---|
| 1150 | if (!b_try_trim_file(&file->data)) { |
|---|
| 1151 | timeout = B_TRIM_TRY_TIMER; |
|---|
| 1152 | goto done; |
|---|
| 1153 | } |
|---|
| 1154 | /* this effectively limits rate of succesfull trims to one each B_TRIM_TIMER */ |
|---|
| 1155 | goto done; |
|---|
| 1156 | } |
|---|
| 1157 | |
|---|
| 1158 | b_trim_try_player(file); |
|---|
| 1159 | if(file->bcm_player==NULL) { |
|---|
| 1160 | BDBG_WRN(("index file is empty, trim can't be activated")); |
|---|
| 1161 | goto done; |
|---|
| 1162 | } |
|---|
| 1163 | rc = trim_bp_bounds(file->bcm_player, file, &firstIndex, &lastIndex); |
|---|
| 1164 | if (rc!=0) { |
|---|
| 1165 | BDBG_WRN(("can't obtain file bounds")); |
|---|
| 1166 | goto done; |
|---|
| 1167 | } |
|---|
| 1168 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex, &first); |
|---|
| 1169 | if (rc!=0) { |
|---|
| 1170 | BDBG_WRN(("can't obtain first position ")); |
|---|
| 1171 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex+1, &first); |
|---|
| 1172 | if (rc!=0) { |
|---|
| 1173 | BDBG_WRN(("..2nd Attempt also failed !")); |
|---|
| 1174 | goto done; |
|---|
| 1175 | } |
|---|
| 1176 | } |
|---|
| 1177 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, lastIndex, &last); |
|---|
| 1178 | if (rc!=0) { |
|---|
| 1179 | BDBG_WRN(("can't obtain last position")); |
|---|
| 1180 | goto done; |
|---|
| 1181 | } |
|---|
| 1182 | |
|---|
| 1183 | BDBG_INSTANCE_MSG(file, ("position %ld:%lu:%lld %ld:%lu:%lld ", |
|---|
| 1184 | firstIndex, first.timestamp,B_GET_OFF_T(&first), lastIndex, last.timestamp, B_GET_OFF_T(&last))); |
|---|
| 1185 | |
|---|
| 1186 | interval = file->cfg.interval*1000; |
|---|
| 1187 | |
|---|
| 1188 | if (last.timestamp - first.timestamp > interval) { |
|---|
| 1189 | long index; |
|---|
| 1190 | off_t off; |
|---|
| 1191 | |
|---|
| 1192 | index = BNAV_Player_FindIndexFromTimestamp(file->bcm_player, last.timestamp - interval); |
|---|
| 1193 | if (index<0) { |
|---|
| 1194 | BDBG_WRN(("can't obtain new index")); |
|---|
| 1195 | goto done; |
|---|
| 1196 | } |
|---|
| 1197 | last = first; /* needed for debuging to save previous first */ |
|---|
| 1198 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, index, &first); |
|---|
| 1199 | if (rc!=0) { |
|---|
| 1200 | BDBG_WRN(("can't obtain new position")); |
|---|
| 1201 | goto done; |
|---|
| 1202 | } |
|---|
| 1203 | BDBG_MSG(("trimming from %d:%u:%lld to %d:%u:%lld", last.index, last.timestamp, B_GET_OFF_T(&last), index, first.timestamp, B_GET_OFF_T(&first))); |
|---|
| 1204 | off = index*file->index_entrysize; |
|---|
| 1205 | BDBG_MSG(("trimming index old %lld new %lld", (int64_t)file->index.trim_off, (int64_t)off)); |
|---|
| 1206 | file->index.trim_off = off; |
|---|
| 1207 | file->index.trim_count = 1; |
|---|
| 1208 | |
|---|
| 1209 | file->index.file->header->trim_gap = (index - file->index.file->header->prev_trim)*file->index_entrysize; |
|---|
| 1210 | |
|---|
| 1211 | file->index.file->header->prev_trim = last.index; |
|---|
| 1212 | |
|---|
| 1213 | off = B_GET_OFF_T(&first) - first.metadataOffset; |
|---|
| 1214 | #ifdef DIRECT_IO_SUPPORT |
|---|
| 1215 | off -= off % B_DATA_ALIGN; |
|---|
| 1216 | #endif |
|---|
| 1217 | BDBG_MSG(("trimming data old %lld new %lld", (int64_t)file->data.trim_off, (int64_t)off)); |
|---|
| 1218 | file->data.trim_off = off; |
|---|
| 1219 | file->data.trim_count = 1; |
|---|
| 1220 | |
|---|
| 1221 | timeout = B_TRIM_TRY_TIMER; /* do a trim on the next timer callout */ |
|---|
| 1222 | } |
|---|
| 1223 | done: |
|---|
| 1224 | file->timer = NEXUS_ScheduleTimer(timeout, b_trim_timer, file); /* schedulle another heartbeat for the trim */ |
|---|
| 1225 | NEXUS_Time_Get(&stop); |
|---|
| 1226 | BDBG_MSG(("trim_timer(%#x) %ldms", (unsigned)file , NEXUS_Time_Diff(&stop, &start))); |
|---|
| 1227 | |
|---|
| 1228 | if (!file->timer) { |
|---|
| 1229 | BDBG_ERR(("trim hearbeat has died")); |
|---|
| 1230 | return; |
|---|
| 1231 | } |
|---|
| 1232 | |
|---|
| 1233 | return; |
|---|
| 1234 | } |
|---|
| 1235 | |
|---|
| 1236 | |
|---|
| 1237 | NEXUS_FifoRecordHandle |
|---|
| 1238 | NEXUS_FifoRecord_Create(const char *fname, const char *indexname) |
|---|
| 1239 | { |
|---|
| 1240 | NEXUS_FifoRecordHandle file; |
|---|
| 1241 | NEXUS_Error rc; |
|---|
| 1242 | |
|---|
| 1243 | if (fname==NULL) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; } |
|---|
| 1244 | if (indexname==NULL) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; } |
|---|
| 1245 | |
|---|
| 1246 | file = BKNI_Malloc(sizeof(*file)); |
|---|
| 1247 | if (!file) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); goto err_alloc; } |
|---|
| 1248 | |
|---|
| 1249 | BKNI_Memset(file, 0, sizeof *file); |
|---|
| 1250 | |
|---|
| 1251 | file->cfg.interval = 30; |
|---|
| 1252 | file->cfg.snapshotInterval = 0; |
|---|
| 1253 | file->cfg.data.soft = 512*1024*1024; |
|---|
| 1254 | file->cfg.data.hard = 1024*1024*1024; |
|---|
| 1255 | file->cfg.data.soft -= file->cfg.data.soft % B_DATA_ALIGN; |
|---|
| 1256 | file->cfg.data.hard -= file->cfg.data.hard % B_DATA_ALIGN; |
|---|
| 1257 | file->cfg.index.soft = 4*1024*1024; |
|---|
| 1258 | file->cfg.index.hard = 8*1024*1024; |
|---|
| 1259 | |
|---|
| 1260 | file->data.trim_count = 0; |
|---|
| 1261 | |
|---|
| 1262 | NEXUS_Time_Get(&file->lastSnapshotTime); |
|---|
| 1263 | |
|---|
| 1264 | file->data.file = bpvrfifo_write_open(fname, true, 0); |
|---|
| 1265 | if (!file->data.file) { goto err_data;} |
|---|
| 1266 | file->data.file->size = file->cfg.data.soft; |
|---|
| 1267 | |
|---|
| 1268 | file->index.trim_count = 0; |
|---|
| 1269 | file->index.file = bpvrfifo_write_open(indexname, false, 2*sizeof(file->data.file->header->data)); |
|---|
| 1270 | if (!file->index.file) { goto err_index;} |
|---|
| 1271 | file->index.file->size = file->cfg.index.soft; |
|---|
| 1272 | |
|---|
| 1273 | file->rd_index = bpvrfifo_read_open(indexname, false, file->index.file); |
|---|
| 1274 | if (!file->rd_index) { goto err_rd_index;} |
|---|
| 1275 | |
|---|
| 1276 | |
|---|
| 1277 | file->self.index = bpvrfifo_write_file(file->index.file); |
|---|
| 1278 | file->self.data = bpvrfifo_write_file(file->data.file); |
|---|
| 1279 | |
|---|
| 1280 | file->self.close = bfile_fifo_close_out; |
|---|
| 1281 | |
|---|
| 1282 | file->index_entrysize = BNAV_GetEntrySize(BNAV_VersionOriginal); /* default */ |
|---|
| 1283 | file->bcm_player = NULL; |
|---|
| 1284 | |
|---|
| 1285 | file->index.trim_count = file->data.trim_count = 0; |
|---|
| 1286 | file->index.trim_off = file->data.trim_off = 0; |
|---|
| 1287 | |
|---|
| 1288 | /* timer shall be the last call in the initialization sequence */ |
|---|
| 1289 | file->timer = NEXUS_ScheduleTimer(B_TRIM_TIMER, b_trim_timer, file); /* schedulle heartbeat for the trim */ |
|---|
| 1290 | if (!file->timer) { goto err_timer; } |
|---|
| 1291 | |
|---|
| 1292 | return file; |
|---|
| 1293 | |
|---|
| 1294 | err_timer: |
|---|
| 1295 | bpvrfifo_read_close(file->rd_index); |
|---|
| 1296 | err_rd_index: |
|---|
| 1297 | bpvrfifo_write_close(file->index.file); |
|---|
| 1298 | err_index: |
|---|
| 1299 | bpvrfifo_write_close(file->data.file); |
|---|
| 1300 | err_data: |
|---|
| 1301 | BKNI_Free(file); |
|---|
| 1302 | err_alloc: |
|---|
| 1303 | return NULL; |
|---|
| 1304 | } |
|---|
| 1305 | |
|---|
| 1306 | NEXUS_FileRecordHandle |
|---|
| 1307 | NEXUS_FifoRecord_GetFile(NEXUS_FifoRecordHandle file) |
|---|
| 1308 | { |
|---|
| 1309 | return &file->self; |
|---|
| 1310 | } |
|---|
| 1311 | |
|---|
| 1312 | NEXUS_Error |
|---|
| 1313 | NEXUS_FifoRecord_GetPosition(NEXUS_FifoRecordHandle file, NEXUS_FilePosition *first, NEXUS_FilePosition *last) |
|---|
| 1314 | { |
|---|
| 1315 | long firstIndex, lastIndex; |
|---|
| 1316 | BNAV_Player_Position pos; |
|---|
| 1317 | int rc; |
|---|
| 1318 | |
|---|
| 1319 | b_trim_try_player(file); |
|---|
| 1320 | if(file->bcm_player==NULL) { |
|---|
| 1321 | BDBG_MSG(("index file is empty, position can't be extracted")); |
|---|
| 1322 | /* fill them with zeros */ |
|---|
| 1323 | if(first) { |
|---|
| 1324 | first->mpegFileOffset = 0; |
|---|
| 1325 | first->indexOffset = NEXUS_FILE_INVALID_POSITION; |
|---|
| 1326 | first->timestamp = NEXUS_FILE_INVALID_POSITION; |
|---|
| 1327 | } |
|---|
| 1328 | if(last) { /* fill them with zeros */ |
|---|
| 1329 | last->mpegFileOffset = 0; |
|---|
| 1330 | last->indexOffset = NEXUS_FILE_INVALID_POSITION; |
|---|
| 1331 | last->timestamp = NEXUS_FILE_INVALID_POSITION; |
|---|
| 1332 | } |
|---|
| 1333 | return NEXUS_SUCCESS; |
|---|
| 1334 | } |
|---|
| 1335 | rc = bp_bounds(file->bcm_player, file, &firstIndex, &lastIndex); |
|---|
| 1336 | if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); } |
|---|
| 1337 | if (first) { |
|---|
| 1338 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex, &pos); |
|---|
| 1339 | if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); } |
|---|
| 1340 | first->indexOffset = pos.index; |
|---|
| 1341 | first->timestamp = pos.timestamp; |
|---|
| 1342 | first->mpegFileOffset = B_GET_OFF_T(&pos); |
|---|
| 1343 | } |
|---|
| 1344 | if (last) { |
|---|
| 1345 | rc = BNAV_Player_GetPositionInformation(file->bcm_player, lastIndex, &pos); |
|---|
| 1346 | if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); } |
|---|
| 1347 | last->indexOffset = pos.index; |
|---|
| 1348 | last->timestamp = pos.timestamp; |
|---|
| 1349 | last->mpegFileOffset = B_GET_OFF_T(&pos); |
|---|
| 1350 | } |
|---|
| 1351 | return NEXUS_SUCCESS; |
|---|
| 1352 | } |
|---|
| 1353 | |
|---|
| 1354 | void |
|---|
| 1355 | NEXUS_FifoRecord_GetSettings(NEXUS_FifoRecordHandle file, NEXUS_FifoRecordSettings *settings) |
|---|
| 1356 | { |
|---|
| 1357 | /* settings are read only, so wa don't need synchronization here */ |
|---|
| 1358 | *settings = file->cfg; |
|---|
| 1359 | return; |
|---|
| 1360 | } |
|---|
| 1361 | |
|---|
| 1362 | |
|---|
| 1363 | NEXUS_Error |
|---|
| 1364 | NEXUS_FifoRecord_SetSettings(NEXUS_FifoRecordHandle file, const NEXUS_FifoRecordSettings *settings) |
|---|
| 1365 | { |
|---|
| 1366 | if ( |
|---|
| 1367 | settings->index.soft <= 2*sizeof(*file->data.file->header) || |
|---|
| 1368 | settings->index.soft >= 2*1024*1024*(off_t)1024 || |
|---|
| 1369 | settings->index.hard <= 2*sizeof(*file->data.file->header) || |
|---|
| 1370 | settings->index.hard >= 2*1024*1024*(off_t)1024 || |
|---|
| 1371 | settings->index.hard < settings->index.soft || |
|---|
| 1372 | settings->data.soft <= B_DATA_ALIGN || |
|---|
| 1373 | settings->data.hard <= B_DATA_ALIGN || |
|---|
| 1374 | settings->data.hard < settings->index.soft ) |
|---|
| 1375 | { |
|---|
| 1376 | return BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1377 | } |
|---|
| 1378 | /* we don't need synchronization here either */ |
|---|
| 1379 | file->cfg = *settings; |
|---|
| 1380 | file->cfg.data.soft -= file->cfg.data.soft % B_DATA_ALIGN; |
|---|
| 1381 | file->cfg.data.hard -= file->cfg.data.hard % B_DATA_ALIGN; |
|---|
| 1382 | BDBG_INSTANCE_MSG(file, ("fifo_out_set: %u index(%lld:%lld) data(%lld:%lld)", file->cfg.interval, file->cfg.data.soft, file->cfg.data.hard, file->cfg.index.soft, file->cfg.index.hard)); |
|---|
| 1383 | /* XXX we should truncate file somewhere, sometime */ |
|---|
| 1384 | b_lock(file->index.file); |
|---|
| 1385 | file->index.file->size = file->cfg.index.soft; |
|---|
| 1386 | b_unlock(file->index.file); |
|---|
| 1387 | b_lock(file->data.file); |
|---|
| 1388 | file->data.file->size = file->cfg.data.soft; |
|---|
| 1389 | b_unlock(file->data.file); |
|---|
| 1390 | return NEXUS_SUCCESS; |
|---|
| 1391 | } |
|---|
| 1392 | |
|---|