void check_write_read_pat(int width, int num, int pat, qio_chtype_t type, qio_hint_t file_hints, qio_hint_t ch_hints, char reopen) { qio_file_t* f; qio_channel_t* writing; qio_channel_t* reading; qioerr err; int memory; char* chhints; char* fhints; char filename[128]; int fd = -1; uint64_t one = 1; uint64_t mask = (one << width) - 1; if( width == 64 ) mask = -1; strcpy(filename,"/tmp/qio_bits_testXXXXXX"); ch_hints = (ch_hints & ~ QIO_CHTYPEMASK) | type; memory = 0; if( (file_hints & QIO_METHODMASK) == QIO_METHOD_MEMORY || (ch_hints & QIO_METHODMASK) == QIO_METHOD_MEMORY ) { memory = 1; } if( memory ) { file_hints = (file_hints & ~ QIO_METHODMASK ) | QIO_METHOD_MEMORY; ch_hints = (ch_hints & ~ QIO_METHODMASK ) | QIO_METHOD_MEMORY; } if( memory && type == QIO_CH_ALWAYS_UNBUFFERED ) return; if( memory && reopen ) return; if( (ch_hints & QIO_METHODMASK) == QIO_METHOD_FREADFWRITE ) { if( (file_hints & QIO_METHODMASK) != QIO_METHOD_FREADFWRITE ) return; } if( (ch_hints & QIO_METHODMASK) == QIO_METHOD_MMAP ) { if( (file_hints & QIO_METHODMASK) != QIO_METHOD_MMAP ) return; } fhints = qio_hints_to_string(file_hints); chhints = qio_hints_to_string(ch_hints); if( verbose ) printf("check_write_read_pat(width=%i, num=%i, pat=%i, type=%i, file_hints=%s %i, ch_hints=%s %i, reopen=%i)\n", width, num, pat, type, fhints, (int) file_hints, chhints, (int) ch_hints, (int) reopen); qio_free(fhints); qio_free(chhints); if( memory ) { err = qio_file_open_mem_ext(&f, NULL, QIO_FDFLAG_READABLE|QIO_FDFLAG_WRITEABLE|QIO_FDFLAG_SEEKABLE, file_hints, NULL); assert(!err); } else { if( reopen ) { fd = mkstemp(filename); close(fd); err = qio_file_open_access(&f, filename, "w", file_hints, NULL); assert(!err); } else { err = qio_file_open_tmp(&f, 0, NULL); assert(!err); } } err = qio_channel_create(&writing, f, ch_hints, 0, 1, 0, INT64_MAX, NULL); assert(!err); for( int i = 0; i < num; i++ ) { uint64_t x; if( pat == 0 ) { if( i & 1 ) x = mask; else x = 0; } else { x = ((uint64_t) i) & mask; } { // check offset int64_t off = qio_channel_offset_unlocked(writing); assert( off == (width * i + 7) / 8 ); } err = qio_channel_write_bits(false, writing, x, width); assert(!err); } qio_channel_release(writing); // Reopen the file if we're doing reopen if( reopen ) { // Close the file. qio_file_release(f); err = qio_file_open_access(&f, filename, "r", file_hints, NULL); assert(!err); } // Rewind the file if( !memory ) { off_t off; sys_lseek(f->fd, 0, SEEK_SET, &off); assert(!err); } err = qio_channel_create(&reading, f, ch_hints, 1, 0, 0, INT64_MAX, NULL); assert(!err); for( int i = 0; i < num; i++ ) { uint64_t got = 0; uint64_t x; if( pat == 0 ) { if( i & 1 ) x = mask; else x = 0; } else { x = ((uint64_t) i) & mask; } { // check offset int64_t off = qio_channel_offset_unlocked(reading); assert( off == (width * i + 7) / 8 ); } //printf("Reading at %lli\n", (long long int) qio_channel_offset_unlocked(reading)); err = qio_channel_read_bits(false, reading, &got, width); assert(!err); //printf("Got %lli\n", (long long int) got); if( got != x ) { printf("Fails (%i %i %i) at %i got=%llx expect=%llx\n", width, num, pat, i, (unsigned long long int) got, (unsigned long long int) x); assert(got == x); break; } } qio_channel_release(reading); // Close the file. qio_file_release(f); if( reopen ) { unlink(filename); } }
// unbounded_channels <= 0 means no, > 0 means yes // -1 means advance. void check_channel(char threadsafe, qio_chtype_t type, int64_t start, int64_t len, int64_t chunksz, qio_hint_t file_hints, qio_hint_t ch_hints, char unbounded_channels, char reopen) { qio_file_t* f; qio_channel_t* writing; qio_channel_t* reading; int64_t offset; int64_t usesz; int64_t end = start + len; int err; unsigned char* chunk; unsigned char* got_chunk; int64_t k; ssize_t amt_written; ssize_t amt_read; char* chhints; char* fhints; FILE* writefp = NULL; FILE* readfp = NULL; int memory; int64_t ch_end = end; char filename[128]; int fd = -1; strcpy(filename,"/tmp/qio_testXXXXXX"); if( unbounded_channels > 0 ) ch_end = INT64_MAX; ch_hints = (ch_hints & ~ QIO_CHTYPEMASK) | type; memory = 0; if( (file_hints & QIO_METHODMASK) == QIO_METHOD_MEMORY || (ch_hints & QIO_METHODMASK) == QIO_METHOD_MEMORY ) { memory = 1; } if( memory ) { file_hints = (file_hints & ~ QIO_METHODMASK ) | QIO_METHOD_MEMORY; ch_hints = (ch_hints & ~ QIO_METHODMASK ) | QIO_METHOD_MEMORY; } if( memory && type == QIO_CH_ALWAYS_UNBUFFERED ) return; if( memory && reopen ) return; if( (ch_hints & QIO_METHODMASK) == QIO_METHOD_FREADFWRITE ) { if( (file_hints & QIO_METHODMASK) != QIO_METHOD_FREADFWRITE ) return; } if( (ch_hints & QIO_METHODMASK) == QIO_METHOD_MMAP ) { if( (file_hints & QIO_METHODMASK) != QIO_METHOD_MMAP ) return; } fhints = qio_hints_to_string(file_hints); chhints = qio_hints_to_string(ch_hints); printf("check_channel(threadsafe=%i, type=%i, start=%lli, len=%lli, chunksz=%lli, file_hints=%s, ch_hints=%s, unbounded=%i, reopen=%i)\n", (int) threadsafe, (int) type, (long long int) start, (long long int) len, (long long int) chunksz, fhints, chhints, (int) unbounded_channels, (int) reopen ); free(fhints); free(chhints); chunk = malloc(chunksz); got_chunk = malloc(chunksz); assert(chunk); assert(got_chunk); if( memory ) { err = qio_file_open_mem_ext(&f, NULL, QIO_FDFLAG_READABLE|QIO_FDFLAG_WRITEABLE|QIO_FDFLAG_SEEKABLE, file_hints, NULL); assert(!err); } else { // Open a temporary file. if( reopen ) { fd = mkstemp(filename); close(fd); err = qio_file_open_access(&f, filename, "w", file_hints, NULL); assert(!err); } else { err = qio_file_open_tmp(&f, file_hints, NULL); assert(!err); } // Rewind the file if (f->fp ) { int got; got = fseek(f->fp, start, SEEK_SET); assert( got == 0 ); } else { off_t off; err = sys_lseek(f->fd, start, SEEK_SET, &off); assert(!err); } } // Create a "write to file" channel. err = qio_channel_create(&writing, f, ch_hints, 0, 1, start, ch_end, NULL); assert(!err); // Write stuff to the file. for( offset = start; offset < end; offset += usesz ) { usesz = chunksz; if( offset + usesz > end ) usesz = end - offset; // Fill chunk. fill_testdata(offset, usesz, chunk); // Write chunk. if( writefp ) { amt_written = fwrite(chunk, 1, usesz, writefp); } else { err = qio_channel_write(threadsafe, writing, chunk, usesz, &amt_written); assert(!err); } assert(amt_written == usesz); } // Attempt to write 1 more byte; we should get EEOF // if we've restricted the range of the channel. // Write chunk. if( unbounded_channels > 0) { // do nothing } else { if( writefp ) { int got; got = fflush(writefp); assert(got == 0); amt_written = fwrite(chunk, 1, 1, writefp); // fwrite might buffer on its own. if( amt_written != 0 ) { got = fflush(writefp); assert(got == EOF); } assert(errno == EEOF); } else { if( unbounded_channels < 0 ) { int times = -unbounded_channels; for( int z = 0; z < times; z++ ) { err = qio_channel_advance(threadsafe, writing, 1); assert( !err ); } } err = qio_channel_write(threadsafe, writing, chunk, 1, &amt_written); assert(amt_written == 0); assert( err == EEOF ); } } qio_channel_release(writing); // Reopen the file if we're doing reopen if( reopen ) { // Close the file. qio_file_release(f); err = qio_file_open_access(&f, filename, "r", file_hints, NULL); assert(!err); } // Check that the file is the right length. if( !memory ) { struct stat stats; err = sys_fstat(f->fd, &stats); assert(!err); assert(stats.st_size == end); } // That was fun. Now start at the beginning of the file // and read the data. // Rewind the file if( !memory ) { off_t off; sys_lseek(f->fd, start, SEEK_SET, &off); assert(!err); } // Read the data. //err = qio_channel_init_file(&reading, type, f, ch_hints, 1, 0, start, end); err = qio_channel_create(&reading, f, ch_hints, 1, 0, start, ch_end, NULL); assert(!err); // Read stuff from the file. for( offset = start; offset < end; offset += usesz ) { usesz = chunksz; if( offset + usesz > end ) usesz = end - offset; // Fill chunk. fill_testdata(offset, usesz, chunk); memset(got_chunk, 0xff, usesz); // Read chunk. if( readfp ) { amt_read = fread(got_chunk, 1, usesz, readfp); } else { err = qio_channel_read(threadsafe, reading, got_chunk, usesz, &amt_read); assert( err == EEOF || err == 0); } assert(amt_read == usesz); // Compare chunk. for( k = 0; k < usesz; k++ ) { assert(got_chunk[k] == chunk[k]); } } if( readfp ) { amt_read = fread(got_chunk, 1, 1, readfp); assert( amt_read == 0 ); assert( feof(readfp) ); } else { if( unbounded_channels < 0 ) { int times = -unbounded_channels; for( int z = 0; z < times; z++ ) { err = qio_channel_advance(threadsafe, reading, 1); assert( !err ); } err = qio_channel_advance(threadsafe, reading, -unbounded_channels); assert( !err ); } err = qio_channel_read(threadsafe, reading, got_chunk, 1, &amt_read); assert( err == EEOF ); } qio_channel_release(reading); //err = qio_channel_destroy(&reading); // Close the file. qio_file_release(f); if( reopen ) { unlink(filename); } free(chunk); free(got_chunk); }