error in C program ring buffer - c

The code below crashes during runtime. I used a couple of online references to come up with the code, and since it compiles thought the issue was somewhere else. But I went over the rest of it and that seems to work fine.
ring_buffer.h
#ifndef RING_BUFFER_H /* Guard against multiple inclusion */
#define RING_BUFFER_H
#include <stddef.h> // Defines NULL
#include <stdbool.h> // Defines true
#include <stdlib.h> // Defines EXIT_FAILURE
#include <stdint.h> // Defines uint32_t
#include <string.h>
typedef struct{
uint8_t * buffer;
uint8_t head;
uint8_t tail;
uint8_t max_length;
}ring_buffer;
void buffer_init(ring_buffer *buff_ptr);
bool buffer_full(ring_buffer *buff_ptr);
bool buffer_empty(ring_buffer *buff_ptr);
bool buffer_write(ring_buffer *buffer, uint8_t data);
bool buffer_read(ring_buffer *buffer, uint8_t * data);
#endif /* _EXAMPLE_FILE_NAME_H */
ring_buffer.c
#include "ring.h"
//ring_buffer UART_buffer; this goes in UART.h
#define UART_RING_BUFFER_SIZE 16
void buffer_init(ring_buffer *buff_ptr)
{ // type casting cause malloc returns void pointer
buff_ptr = (ring_buffer*)malloc(sizeof(ring_buffer)); // assign address to the uart_ring_buffer of size ring_buffer
memset(&buff_ptr, 0x00, sizeof(buff_ptr)); // set all locations to NULL so that if read before write conditions occur, garbage data is not read
buff_ptr->buffer = (uint8_t*)malloc(UART_RING_BUFFER_SIZE * sizeof(uint8_t)); // data buffer assigned of size max_length
memset(&buff_ptr->buffer, 0x00, sizeof(uint8_t));
buff_ptr-> head = 0;
buff_ptr-> tail = 0;
buff_ptr-> max_length = UART_RING_BUFFER_SIZE;
}
bool buffer_write(ring_buffer *buff_ptr, uint8_t data)
{
int next = buff_ptr->head + 1; // increment head to point to location in which data will be written to
if(next >= buff_ptr->max_length)
next = 0;
if(next == buff_ptr->tail) //check for buffer full condition
return -1; // indicate write failed, buffer full
buff_ptr->buffer[buff_ptr->head] = data;
buff_ptr->head = next; // update head to point to current location
return 0; // indicates buffer write success
}
bool buffer_read(ring_buffer *buff_ptr, uint8_t *data)
{
int next = buff_ptr->tail+1;
if(next >= buff_ptr->max_length)
next = 0;
if(buff_ptr->head == buff_ptr->tail) // check for buffer empty
return -1; // indicates read failed, buffer empty
*data = buff_ptr->buffer[buff_ptr->tail];
buff_ptr->tail = next;
return 0;
}
bool buffer_full(ring_buffer *buff_ptr) //NOT PROPER LOGIC
{
int next = buff_ptr->head + 1; // increment head to point to location in which data will be written to
if(next >= buff_ptr->max_length)
next = 0;
if(next == buff_ptr->tail) //check for buffer full condition
return 1;
else
return 0;
}
bool buffer_empty(ring_buffer *buff_ptr)
{
if(buff_ptr->head == buff_ptr->tail) // check for buffer empty
return 1; // indicates read failed, buffer empty
return 0;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "ring.h"
ring_buffer UART_FIFO;
int main()
{
char x;
buffer_init(&UART_FIFO);
printf("data in goes here: ");
while (1)
{
scanf("%c",&x);
buffer_write(&UART_FIFO, x);
}
}
let me know if there are any obvious mistakes, kinda new to using pointers, have done verilog and FPGA related stuff previously.

I found the issue:
memset(&buff_ptr, 0x00, sizeof(buff_ptr));
Has to be:
memset(buff_ptr, 0x00, sizeof(ring_buffer));

buff_ptr = (ring_buffer*)malloc(sizeof(ring_buffer)); // assign address to the uart_ring_buffer of size ring_buffer
memset(&buff_ptr, 0x00, sizeof(buff_ptr)); // set all locations to NULL so that if read before write conditions occur, garbage data is not read
that buff_ptr is already a pointer passing reference of buff_ptr to memset doesn't do any good remove the &
memset(&buff_ptr, 0x00, sizeof(buff_ptr)); //

Related

Kernel hashtable crash while iterating

I am writing two basic syscalls. One adds nodes containing a userspace string to the hash table, and the other dumps the contents of the table.
After adding a few items and calling the dump function, it prints one item then crashes with BUG: unable to handle kernel paging request at
I tried to remove all code related to the userspace string to make sure the error wasn't coming from that. I adding a table_node with only next and key but I ran into the same error.
I have a feeling that I am overlooking something very simple. Does anything jump out with how I am adding or walking the table?
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/slab.h>
#include <linux/hashtable.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
DEFINE_HASHTABLE(table, 10);
struct table_node {
unsigned long key;
struct hlist_node next;
char * name;
};
SYSCALL_DEFINE1(add_to_table, const char *, name) {
struct table_node newNode;
long strLen;
long copied;
int maxLen = 100;
// Get length of userspace string
strLen = strnlen_user(name, maxLen);
if (strLen <=0 || strLen > maxLen){
return -EINVAL;
}
char s[strLen];
newNode.name = s;
// Copy string to kernel space
copied = strncpy_from_user(newNode.name, name, strLen);
if (copied <= 0 || copied > maxLen){
return -EINVAL;
}
newNode.key = (hash(name) % HASH_SIZE(table));
hash_add(table, &newNode.next, newNode.key);
return 0;
}
SYSCALL_DEFINE0(dump_table) {
int bkt = 0;
table_node * ptr = NULL;
// Print each entry in the hash table
hash_for_each_(table, bkt, ptr, next){
printk("\tkey=%lu,bucket %d\n", ptr->key bkt);
}
return 0;
}
Thank you for the help!
Kamil's solution worked.
I forgot to dynamically allocate memory. Adding these two lines resolved my issue.
table_node *newNode = kmalloc(sizeof(table_node), GFP_KERNEL);
newNode-fname = kmalloc(strLen * sizeof(char)+1, GFP_KERNEL);

return address of part of a circular array

So i have a circular array of max size 2097152 and i want it to fill up to 524288 and return the address that holds that 524288 indices. Then fills up another 524288 and do the same. and keeps doing that since it's a circular array.
I am getting stream of data via TCP. This data comes in different sizes, but for now I'm just trying to fill up my array with numbers.
I'm not sure how to approach this.
I have this so far:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <stdbool.h>
typedef struct circular_buffer
{
void *buffer; // data buffer
void *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
void *head; // pointer to head
void *tail; // pointer to tail
} circular_buffer;
void cb_init(circular_buffer *cb, size_t capacity, size_t sz)
{
cb->buffer = malloc(capacity * sz);
if(cb->buffer == NULL)
{
printf("myError: Buffer returned Null");
}
cb->buffer_end = (char *)cb->buffer + capacity * sz;
cb->capacity = capacity;
cb->count = 0;
cb->sz = sz;
cb->head = cb->buffer;
cb->tail = cb->buffer;
}
void cb_free(circular_buffer *cb)
{
free(cb->buffer);
// clear out other fields too, just to be safe
}
void cb_push_back(circular_buffer *cb, const void *item)
{
if(cb->count == cb->capacity)
// handle error
memcpy(cb->head, item, cb->sz);
cb->head = (char*)cb->head + cb->sz;
if(cb->head == cb->buffer_end)
cb->head = cb->buffer;
cb->count++;
}
int main()
{
int *arr = malloc (BUFFER_LEN * sizeof *arr);
int i;
for(i = 0; i <= BUFFER_LEN; i++) { arr[i] = i; }
return(0);
}
You can return the start of your data with the address-of operator (&) and access this like an array. e.g.
char *fill_cb(circular_buffer *cb, char *buf, size_t sz)
{
/* Assume there is room in the buffer: caller must check before calling this function */
if(cb->tail + sz < cb->buffer_end) {
memcpy(cb->tail, buf, sz);
cb->tail += sz;
cb->count += sz;
return cb->tail - sz;
} else {
size_t tail_room = cb->buffer_end - cb->tail;
memcpy(cb->tail, buf, tail_room);
memcpy(cb->buffer, buf + tail_room, sz - tail_room);
cb->tail = cb->buffer + sz - tail_room;
return cb->buffer_end - tail_room;
}
}
Now you can use this pointer and access the memory in the circular buffer much like an array
e.g.
my_data = fill_cb(cb, buf, 20);
do_stuff(my_data[10]);
However, this will only work when you didn't wrap! The array access expects memory to be contiguous. But we wrapped inside the circular buffer. So returning a pointer to the start of the data inserted isn't useful to the using program. You need to write access methods to get the data out of the circular buffer. In C++ you might overload [] to make it look like an array. In C you need to write functions for these.
Basically, you are hoping that there can be a memory region which is wrapped like your diagram, but memory is flat and if you return the address of the start of the data and access from there continuously then you will read past the end of the circular buffer (and in to undefined behaviour).
I've done a few of these circular buffer / ring queues before. Below is one of the versions I've used. The source code is complete and has a demo/diagnostic program. It should be buildable and runnable without [much :-)] change.
The central core of this, embodied in the .h file has been floating around my code base for 10-20 years, so it's got some mileage on it. Because of this, it has a few things that I've added based on my actual usage and experience with it.
There are a few differences from your version. Not necessarily better or worse--just different. Hopefully, this will give you some ideas for your own code.
For one, there is only one pointer to the start of the queue. The enqueue element [which you named cb_head] is an index rather than a pointer. Likewise for the dequeue [cb_tail]. From my experience, this makes the code a bit simpler, is on-par speedwise [and can sometimes be faster].
Although I have versions that use pointers to everything, they have pointers to a specific [struct] type, rather than void * pointers and a "sizeof" element. But, to do this in C, requires a lot of CPP macro [or metaprogramming] trickery, to get the effect of a C++ template.
One of the other reasons for using indexes vs. pointers is creating multithread/thread safe queues. This hasn't been designed into this particular version, but there is a cursory example with qrngnew_lck that would use a lock (e.g. pthread_mutex_lock/pthread_mutex_unlock).
Also, as an alternative to a mutex, it is possible to use primitives from stdatomic.h (e.g. atomic_compare_exchange*) to change the enqueue/dequeue values. It is much easier to use this if these values are int vs void *
When dealing with a lot of data (e.g. from recv), what's most useful is to know how many cells can be copied in a single chunk (i.e. memcpy), rather than doing individual pushes and pops [which is slow].
Also, maintaining a separate count of number of elements in queue isn't necessary as this is easily calculated from the enqueue and dequeue values.
Things of interest are:
total number of free cells available to enqueue data
number of contiguous free cells available for a single memcpy
total number of filled cells pending to be dequeued
number of contiguous filled cells pending that can extracted with a single memcpy
Anyway, the code is below. It is three files: qrng.h, qrng.c, and qrngdemo.c.
Sorry about the qrng*. It's a personal signature style (i.e. "quirk"). It could just as easily have been ring everywhere [but, because I have several different versions, I use this naming to avoid collisions in C's namespace]. It could also have been [say] cb everywhere :-)
qrng.h:
// ovrlib/qrng.h -- ring queue control
#ifndef _ovrlib_qrng_h_
#define _ovrlib_qrng_h_
#define QRNGMAGIC 0xDEAFDEAD
#define QRNGINLINE static inline
#define _QRNGOFF(_itm) \
((long) _itm)
#define QRNGOFF(_qrng,_itm) \
_QRNGOFF(_qrng->_itm)
#define QRNG_FMT \
"deq=%ld enq=%ld pend=%ld/%ld avail=%ld/%ld qmax=%ld"
#define QRNG_PRT(_qrng) \
QRNGOFF(_qrng,qrng_deq), \
QRNGOFF(_qrng,qrng_enq), \
_QRNGOFF(qrng_pend_buf(_qrng)), \
_QRNGOFF(qrng_pend_tot(_qrng)), \
_QRNGOFF(qrng_avail_buf(_qrng)), \
_QRNGOFF(qrng_avail_tot(_qrng)), \
QRNGOFF(_qrng,qrng_qmax)
// pointer to queue data item
// NOTES:
// (1) _always_ use void *
// (2) the way this is used, setting this to _anything_ else will _not_ work
typedef void *queitm_p;
typedef const void *queitm_pc;
// queue index
// NOTES:
// (1) _must_ be signed
// (2) for most queues, an int is sufficient
#ifdef QRNG_BIGIDX
typedef long qidx_t;
#else
typedef int qidx_t;
#endif
typedef long qlen_t;
typedef unsigned int u32;
typedef struct quering_struct quering_t;
typedef quering_t *quering_p;
typedef const quering_t *quering_pc;
struct quering_struct {
u32 qrng_magic; // magic number
u32 qrng_stat; // status
int qrng_algn[2]; // align to 64 byte boundary
// WARNING:
// (1) accesses to these via sysxchgl require them in
// _exactly_ this order -- do _not_ reorder these
// (2) for 64b mode (cmpxchg16b), these must be aligned to a 16 byte
// boundary
qidx_t qrng_deq; // dequeue pointer
qidx_t qrng_enq; // enqueue pointer
qidx_t qrng_siz; // size of queitm_t
queitm_p qrng_base; // base address of ring buffer
qidx_t qrng_qmax; // number of queue elements
};
// equates to status
#define QRNGALLOC (1u << 0) // 1=qrng_base is allocated on heap
// qrng_len -- get byte offset/length from index/count
QRNGINLINE qlen_t
qrng_len(quering_p qrng,qidx_t idx)
{
qlen_t len;
len = idx;
len *= qrng->qrng_siz;
return len;
}
// qrng_ptr -- get flat pointer to queue element
QRNGINLINE queitm_p
qrng_ptr(quering_p qrng,qidx_t idx)
{
queitm_p ptr;
ptr = qrng->qrng_base;
ptr += qrng_len(qrng,idx);
return ptr;
}
// qrng_wrap_dec -- wrap queue index after decrement
QRNGINLINE qidx_t
qrng_wrap_dec(quering_p qrng,qidx_t qitm,qidx_t inc)
{
qitm -= inc;
if (qitm < 0)
qitm += qrng->qrng_qmax;
return qitm;
}
// qrng_wrap_inc -- wrap queue index after increment
QRNGINLINE qidx_t
qrng_wrap_inc(quering_p qrng,qidx_t qitm,qidx_t inc)
{
qidx_t dif;
qitm += inc;
dif = qitm - qrng->qrng_qmax;
if (dif >= 0)
qitm = dif;
return qitm;
}
// qrng_reset -- reset queue pointers
QRNGINLINE void
qrng_reset(quering_p qrng)
{
qrng->qrng_enq = 0;
qrng->qrng_deq = 0;
}
// qrng_full -- decide if qrng queue is full
// RETURNS: 1=full
QRNGINLINE int
qrng_full(quering_p qrng)
{
qidx_t qenq;
qenq = qrng_wrap_inc(qrng,qrng->qrng_enq,1);
return (qenq == qrng->qrng_deq);
}
// _qrng_empty -- decide if qrng queue is empty
// RETURNS: 1=empty
QRNGINLINE int
_qrng_empty(quering_p qrng,qidx_t enq)
{
return (qrng->qrng_deq == enq);
}
// qrng_empty -- decide if qrng queue is empty
// RETURNS: 1=empty
QRNGINLINE int
qrng_empty(quering_p qrng)
{
return _qrng_empty(qrng,qrng->qrng_enq);
}
// qrng_avail_buf -- amount that can be added by single memcpy
QRNGINLINE qidx_t
qrng_avail_buf(quering_p qrng)
{
qidx_t len;
len = qrng->qrng_deq - qrng->qrng_enq;
if (len <= 0) {
len = qrng->qrng_qmax - qrng->qrng_enq;
if (qrng->qrng_deq == 0)
--len;
}
else
--len;
return len;
}
// qrng_avail_tot_ptr -- total amount that can be added
QRNGINLINE qidx_t
qrng_avail_tot_ptr(quering_p qrng,qidx_t deq,qidx_t enq)
{
qidx_t len;
len = deq - enq;
if (len <= 0)
len += qrng->qrng_qmax;
--len;
return len;
}
// qrng_avail_tot -- total amount that can be added
QRNGINLINE qidx_t
qrng_avail_tot(quering_p qrng)
{
return qrng_avail_tot_ptr(qrng,qrng->qrng_deq,qrng->qrng_enq);
}
// qrng_pend_buf -- amount that may be dequeued by single memcpy
QRNGINLINE qidx_t
qrng_pend_buf(quering_p qrng)
{
qidx_t len;
len = qrng->qrng_enq - qrng->qrng_deq;
if (len < 0)
len = qrng->qrng_qmax - qrng->qrng_deq;
return len;
}
// qrng_pend_tot -- total amount that may be dequeued
QRNGINLINE qidx_t
qrng_pend_tot(quering_p qrng)
{
qidx_t len;
len = qrng->qrng_enq - qrng->qrng_deq;
if (len < 0)
len += qrng->qrng_qmax;
return len;
}
// qrng_deq_buf -- dequeue buffer from qrng queue
QRNGINLINE void
qrng_deq_buf(quering_p qrng,qidx_t inclen)
// inclen -- amount to increment
{
qrng->qrng_deq = qrng_wrap_inc(qrng,qrng->qrng_deq,inclen);
}
// qrng_enq_buf -- enqueue buffer into qrng queue
QRNGINLINE void
qrng_enq_buf(quering_p qrng,qidx_t inclen)
// inclen -- amount to increment
{
qrng->qrng_enq = qrng_wrap_inc(qrng,qrng->qrng_enq,inclen);
}
// /home/cae/OBJ/ovrgen/ovrlib/qrng.proto -- prototypes
// FILE: /home/cae/preserve/ovrstk/ovrlib/qrng.c
// ovrlib/qrng -- ring queue common control
// _qrngnoalloc -- handle alloc failure
void
_qrngnoalloc(quering_p qrng,int sverr);
// qrng_setup -- passive setup
// RETURNS: 1=initialized
int
qrng_setup(quering_p qrng,queitm_p bp,qidx_t siz,qidx_t cnt);
// qrng_alloc -- allocate ring queue
queitm_p
qrng_alloc(quering_p qrng,qidx_t cnt);
// qrng_free -- free queue
void
qrng_free(quering_p qrng);
// qrng_deq_sgl -- dequeue single element from qrng queue
queitm_p
qrng_deq_sgl(quering_p qrng);
// qrng_enq_sgl -- enqueue single element into qrng queue
queitm_p
qrng_enq_sgl(quering_p qrng,queitm_p qitm);
// qrngnew_lck -- enqueue multiple items into qrng queue (syslock)
// RETURNS: pointer to items to store (or NULL)
queitm_p
qrngnew_lck(quering_p qrng,qidx_t cnt,quering_p rlsdeq);
// _qrngnew_init -- do special type-specific initialization
void
_qrngnew_init(queitm_p qitm);
// _qrngnew_onfull -- decide if capture is stopped because queue is full
queitm_p
_qrngnew_onfull(quering_p qrng,qidx_t rtn);
// qrngcowbrk -- break copy-on-write
void
qrngcowbrk(quering_p qrng);
// qrngfault -- output fault
void
qrngfault(quering_p qrng,const char *fmt,...) __attribute__((__format__(__printf__,2,3)));
#endif
qrng.c:
// ovrlib/qrng -- ring queue common control
#include <qrng.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#if 0
#define zprt(_lvl,_fmt...) fprintf(stderr,_fmt)
#else
#define zprt(_lvl,_fmt...) /**/
#endif
// _qrngnoalloc -- handle alloc failure
void
_qrngnoalloc(quering_p qrng,int sverr)
{
qrngfault(qrng,"_qrngnoalloc: unable to allocate buffer -- %s\n",
strerror(sverr));
}
// qrng_setup -- passive setup
// RETURNS: 1=initialized
int
qrng_setup(quering_p qrng,queitm_p bp,qidx_t siz,qidx_t cnt)
{
int initflg;
#ifdef CPLXCVTLNG
if ((CPLXCVTLNG(qrng) % 16) != 0)
qrngfault("qrngsetup: alignment fault -- qrng=%p\n",qrng);
#endif
do {
initflg = (qrng->qrng_magic != QRNGMAGIC);
if (initflg)
memset(qrng,0,sizeof(quering_t));
qrng->qrng_magic = QRNGMAGIC;
qrng->qrng_siz = siz;
// allocate space for queue
if (bp == NULL)
bp = qrng_alloc(qrng,cnt);
else
qrng_free(qrng);
qrng->qrng_base = bp;
qrng->qrng_qmax = cnt;
// break copy-on-write
qrngcowbrk(qrng);
} while (0);
qrng_reset(qrng);
return initflg;
}
// qrng_alloc -- allocate ring queue
queitm_p
qrng_alloc(quering_p qrng,qidx_t cnt)
{
queitm_p qitm;
int sverr;
do {
qitm = qrng->qrng_base;
// don't realloc if old and new sizes match -- just reset the pointers
if (qitm != NULL) {
if (cnt == qrng->qrng_qmax) {
break;
}
}
// free the old queue
qrng_free(qrng);
// allocate the queue
qitm = calloc(cnt,qrng->qrng_siz);
sverr = errno;
// fault on alloc failure
if (qitm == NULL)
_qrngnoalloc(qrng,sverr);
qrng->qrng_stat |= QRNGALLOC;
} while (0);
qrng_reset(qrng);
return qitm;
}
// qrng_free -- free queue
void
qrng_free(quering_p qrng)
{
queitm_p qitm;
do {
qitm = qrng->qrng_base;
if (qitm == NULL) {
break;
}
if (qrng->qrng_stat & QRNGALLOC) {
free(qitm);
}
} while (0);
qrng->qrng_base = NULL;
qrng->qrng_stat &= ~QRNGALLOC;
}
// qrng_deq_sgl -- dequeue single element from qrng queue
queitm_p
qrng_deq_sgl(quering_p qrng)
{
qidx_t deq;
queitm_p qrtn;
do {
if (qrng_empty(qrng)) {
qrtn = NULL;
break;
}
deq = qrng->qrng_deq;
qrtn = qrng_ptr(qrng,deq);
qrng->qrng_deq = qrng_wrap_inc(qrng,deq,1);
} while (0);
return qrtn;
}
// qrng_enq_sgl -- enqueue single element into qrng queue
queitm_p
qrng_enq_sgl(quering_p qrng,queitm_p qitm)
// qitm -- item to enqueue (if NULL, caller will do copy on return)
{
qidx_t enq;
queitm_p qrtn;
do {
if (qrng_full(qrng)) {
qrtn = NULL;
break;
}
enq = qrng->qrng_enq;
qrtn = qrng_ptr(qrng,enq);
// we give the caller the option of doing the copy manually or letting
// us do it
if (qitm != NULL)
memcpy(qrtn,qitm,qrng->qrng_siz);
qrng->qrng_enq = qrng_wrap_inc(qrng,enq,1);
} while (0);
return qrtn;
}
// qrngnew_lck -- enqueue multiple items into qrng queue (syslock)
// RETURNS: pointer to items to store (or NULL)
queitm_p
qrngnew_lck(quering_p qrng,qidx_t cnt,quering_p rlsdeq)
{
qidx_t nenq;
qidx_t ndeq;
qidx_t odeq;
qidx_t oenq;
int stopflg;
int wflg;
int dflg;
int ovflg;
queitm_p optr;
stopflg = 0;
// lock it
//SYSLOCKQ(&qrng->qrng_lock,0);
do {
// grab the old values
odeq = qrng->qrng_deq;
oenq = qrng->qrng_enq;
do {
// point to one beyond where we wish to store
nenq = qrng_wrap_inc(qrng,oenq,cnt);
// decide if we wrapped the enqueue pointer
wflg = (nenq < oenq);
// decide if dequeue increment is positive (non-negative)
dflg = (nenq >= odeq);
// decide on overflow
// NOTE: there is an elaborate explanation for the overflow
// logic in qrng.m5m
if (oenq >= odeq)
ovflg = wflg && dflg;
else
ovflg = (wflg != dflg);
// [initial] filling of queue:
// (1) enq was higher than deq and it did _not_ wrap
// (2) enq was lower than deq and it did _not_ touch/go over
if (! ovflg) {
ndeq = odeq;
break;
}
// advance the dequeue pointer to make room
ndeq = qrng_wrap_inc(qrng,nenq,1);
} while (0);
// allow caller to "release" the dequeued nodes
if (rlsdeq != NULL) {
rlsdeq->qrng_deq = odeq;
rlsdeq->qrng_enq = ndeq;
}
// lay down the new pointers
qrng->qrng_enq = nenq;
qrng->qrng_deq = ndeq;
} while (0);
// zap the type (ASAP)
// NOTE: there is a slight (virtually non-existent) race condition here
// which only occurs if we get held off too long and a dump begins
do {
if (stopflg) {
optr = _qrngnew_onfull(qrng,oenq);
break;
}
optr = qrng_ptr(qrng,oenq);
_qrngnew_init(optr);
} while (0);
// unlock it
//SYSUNLOCKQ(&qrng->qrng_lock);
return optr;
}
// _qrngnew_init -- do special type-specific initialization
void
_qrngnew_init(queitm_p qitm)
{
//ARGV_USED(qitm);
}
// _qrngnew_onfull -- decide if capture is stopped because queue is full
queitm_p
_qrngnew_onfull(quering_p qrng,qidx_t rtn)
{
queitm_p ptr;
qrngfault(qrng,"qrngnew: stop on full\n");
ptr = NULL;
return ptr;
}
// qrngcowbrk -- break copy-on-write
void
qrngcowbrk(quering_p qrng)
{
qlen_t len;
len = qrng_len(qrng,qrng->qrng_qmax);
if (len > 0)
memset(qrng->qrng_base,0,len);
}
// qrngfault -- output fault
void
qrngfault(quering_p qrng,const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
vfprintf(stderr,fmt,ap);
va_end(ap);
exit(1);
}
qrngdemo.c:
// qrngdemo/qrngdemo -- test/demo program for qrng
#include <qrng.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int opt_v;
qidx_t opt_M;
int opt_T;
#define dbgprt(_fmt...) \
do { \
if (opt_v) \
printf(_fmt); \
} while (0)
#define fault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
quering_t sampque;
#ifndef MAXCNT
#if 0
#define MAXCNT 524288
#else
#define MAXCNT 337
#endif
#endif
typedef struct {
unsigned int samp_pos;
unsigned int samp_neg;
} sample_t;
typedef sample_t *sample_p;
unsigned int filloff;
unsigned int cmpoff;
sample_p temp;
// sampsetup -- do setup of sample queue
void
sampsetup(quering_p sampq)
{
if (opt_M < 3)
opt_M = 3;
qrng_setup(sampq,NULL,sizeof(sample_t),opt_M);
temp = calloc(opt_M + 10,sizeof(sample_t));
}
// randval -- get random count
qidx_t
randval(qidx_t max)
{
qidx_t cnt;
cnt = rand() % opt_M;
if (cnt <= 0)
cnt = 1;
if (cnt > max)
cnt = max;
return cnt;
}
// fill -- fill queue
void
fill(quering_p sampq)
{
sample_p samp;
qidx_t addcnt;
qidx_t maxcnt;
qidx_t xcnt;
qidx_t idx;
maxcnt = qrng_avail_tot(sampq);
addcnt = randval(maxcnt);
dbgprt("fill: ENTER maxcnt=%ld addcnt=%ld\n",
_QRNGOFF(maxcnt),_QRNGOFF(addcnt));
// fill linear buffer
for (idx = 0; idx < addcnt; ++idx) {
samp = &temp[idx];
samp->samp_pos = filloff;
samp->samp_neg = ~filloff;
filloff += 1;
}
dbgprt("fill: TEMP %8.8X/%8.8X\n",
temp[0].samp_pos,temp[addcnt - 1].samp_pos);
// copy linear buffer into ring queue
for (idx = 0; addcnt > 0; idx += xcnt, addcnt -= xcnt) {
xcnt = qrng_avail_buf(sampq);
if (xcnt > addcnt)
xcnt = addcnt;
if (xcnt <= 0)
break;
dbgprt("fill: COPY %8.8X/%8.8X -- xcnt=%ld " QRNG_FMT "\n",
temp[idx].samp_pos,temp[idx + xcnt - 1].samp_pos,
_QRNGOFF(xcnt),
QRNG_PRT(sampq));
memcpy(qrng_ptr(sampq,sampq->qrng_enq),&temp[idx],qrng_len(sampq,xcnt));
qrng_enq_buf(sampq,xcnt);
}
dbgprt("fill: EXIT " QRNG_FMT "\n",QRNG_PRT(sampq));
}
// cmp -- compare queue
void
cmp(quering_p sampq)
{
sample_p samp;
qidx_t cmpcnt;
qidx_t maxcnt;
qidx_t xcnt;
qidx_t chkcnt;
qidx_t idx;
maxcnt = qrng_pend_tot(sampq);
cmpcnt = randval(maxcnt);
dbgprt("cmp: ENTER maxcnt=%ld cmpcnt=%ld\n",
_QRNGOFF(maxcnt),_QRNGOFF(cmpcnt));
// copy data from ring queue into linear buffer
chkcnt = 0;
for (idx = 0; cmpcnt > 0; idx += xcnt, cmpcnt -= xcnt) {
xcnt = qrng_pend_buf(sampq);
if (xcnt > cmpcnt)
xcnt = cmpcnt;
if (xcnt <= 0)
break;
chkcnt += xcnt;
memcpy(&temp[idx],qrng_ptr(sampq,sampq->qrng_deq),qrng_len(sampq,xcnt));
dbgprt("cmp: COPY %8.8X/%8.8X -- xcnt=%ld " QRNG_FMT "\n",
temp[idx].samp_pos,temp[idx + xcnt - 1].samp_pos,
_QRNGOFF(xcnt),
QRNG_PRT(sampq));
qrng_deq_buf(sampq,xcnt);
}
if (chkcnt > 0)
dbgprt("cmp: TEMP %8.8X/%8.8X chkcnt=%ld\n",
temp[0].samp_pos,temp[chkcnt - 1].samp_pos,_QRNGOFF(chkcnt));
// check linear buffer
for (idx = 0; idx < chkcnt; ++idx) {
samp = &temp[idx];
if ((samp->samp_pos != cmpoff) || (samp->samp_neg != ~cmpoff))
fault("cmp: failure -- idx=%d samp_pos=%8.8X cmpoff=%8.8X\n",
idx,samp->samp_pos,cmpoff);
cmpoff += 1;
}
dbgprt("cmp: EXIT " QRNG_FMT "\n",QRNG_PRT(sampq));
}
// main -- main program
int
main(int argc,char **argv)
{
char *cp;
--argc;
++argv;
opt_M = MAXCNT;
opt_T = 10000000;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'M':
opt_M = strtol(cp,&cp,10);
break;
case 'T':
opt_T = strtol(cp,&cp,10);
break;
case 'v':
opt_v = 1;
break;
}
}
sampsetup(&sampque);
for (int iter = opt_T; iter >= 0; --iter) {
fill(&sampque);
cmp(&sampque);
}
qrng_free(&sampque);
return 0;
}

modify fflush() that guarantee calling ungetc() twice in a row in C

I'm a C beginner, I want to call ungetc() twice in a row although I know in regular C it is not permitted. Someone told me I can modify Fflush() to do this job, however I don't know how to do it.
Here is my code, my Fflush only allow one ungetc(), I want it to allow twice.
#define altUngetc(c, fp) ((fp)->next > (fp)->buffer && (c) != EOF ? \
*--(fp)->next = (c) : EOF)
int altGetc(ALT_FILE *fp) {
if (fp->next == fp->buffer + fp->bufSize)
altFflush(fp);
return fp->flags & FILE_ATEOF ? EOF : *fp->next++;
}
int altFflush(ALT_FILE *fp) {
int res;
if (fp->fd < 0 || fp->flags & FILE_ATEOF)
return EOF;
if (fp->flags & FILE_READ) {
res = read(fp->fd, fp->buffer, BUF_SIZE);
if (res == 0)
fp->flags |= FILE_ATEOF;
fp->bufSize = res;
fp->next = fp->buffer;
}
else {
res = write(fp->fd, fp->buffer, fp->next - fp->buffer);
fp->next = fp->buffer;
}
return res < 0 ? EOF : 0;
}
As wisely mentioned in the comments, you should probably first learn to work with the rules instead of trying to break them. However, we're here to answer the question, and that means to break the rules! Take into account that neither fflush(), setbuf(), or setvbuf() would work here for different reasons.
First of all, at least four custom functions are required. One to create a "proxy buffer" relating to a file (called just after fopen()), one to destroy it (called just before fclose(), one to do the actual ungetting (replacement for ungetc(), and one to to retrieve a char from the file (replacement for fgetc(). Unfortunately, this means that performing fscanf(), fflush(), etc... on the stream will yield you bad and ugly results. You would have to rewrite all of stdio!
First of all, let's call all of our new stuff xtdio ("extended stdio"), so, first of all comes xtdio.h...
#ifndef __XTDIO_H__
#define __XTDIO_H__
#include <stdio.h>
typedef struct
{
FILE *file;
char *buffer;
size_t buffer_size;
size_t buffer_usage;
size_t buffer_tail_offset;
} XFILE;
/* I know this is not the best of API design, but I need to be
* compatible with stdio's API.
*/
XFILE *xwrap(FILE *file, size_t max_ungets);
void xunwrap(XFILE *xfile);
int xgetc(XFILE *xfile);
int xungetc(int ch, XFILE *xfile);
#endif
Then, in the interesting side of the fence, comes xtdio.c...
#include <stdlib.h>
#include <stdio.h>
#include "xtdio.h"
/* Create a XFILE wrapper, along with its respective buffer
* of 'max_ungets' size, around 'file'.
*/
XFILE *xwrap(FILE *file, size_t max_ungets)
{
XFILE *xfile = malloc(sizeof(XFILE));
if(xfile == NULL)
return NULL;
xfile->file = file;
xfile->buffer = malloc(max_ungets);
if(xfile->buffer == NULL) {
free(xfile);
return NULL;
}
xfile->buffer_size = max_ungets;
xfile->buffer_usage = 0;
xfile->buffer_tail_offset = 0;
return xfile;
}
/* Undo what 'xwrap()' did.
*/
void xunwrap(XFILE *xfile)
{
free(xfile->buffer);
free(xfile);
}
/* Check if there's something in the XFILE's
* buffer, and return it. Otherwise, fallback
* onto 'fgetc()'.
*/
int xgetc(XFILE *xfile)
{
if(xfile->buffer_usage == 0)
return fgetc(xfile->file);
if(xfile->buffer_tail_offset == 0)
xfile->buffer_tail_offset = xfile->buffer_size - 1;
else
xfile->buffer_tail_offset--;
xfile->buffer_usage--;
return xfile->buffer[xfile->buffer_tail_offset];
}
/* Here's the interesting part! If there's room in the
* buffer, it puts 'ch' in its front. Otherwise, returns
* an error.
*/
int xungetc(int ch, XFILE *xfile)
{
if(xfile->buffer_usage == xfile->buffer_size)
return EOF; //TODO: Set errno or something
xfile->buffer[xfile->buffer_tail_offset++] = (char)ch;
xfile->buffer_tail_offset %= xfile->buffer_size;
xfile->buffer_usage++;
return ch;
}
The smallish xtdio library will allow you to perform as many ungets as you pass to xwrap()'s parameter. Each XFILE has a buffer with the ungotten characters. When you xgetc(), it first checks if there's something on the buffer and retrieves it. Otherwise, it fallbacks to fgetc(). Example usage case...
#include <stdio.h>
#include <string.h>
#include "xtdio.h"
int main()
{
const char *my_string = "I just ungot this same long string in standard and compliant C! No more one-char limits on ungetc()!\n";
const size_t my_string_len = strlen(my_string);
XFILE *xtdin = xwrap(stdin, my_string_len);
if(xtdin == NULL) {
perror("xwrap");
return 1;
}
for(size_t i = my_string_len; i != 0; i--)
xungetc(my_string[i - 1], xtdin);
int ch;
while((ch = xgetc(xtdin)) != EOF)
putchar(ch);
xunwrap(xtdin);
return 0;
}
xtdio can be further improved, by adding things such as xrewrap() to extend/shrink the buffer's size.
There's an even better solution, and it is to refactor your code, and follow the conventions, so that you don't have to ungetc() twice. xtdio is just a proof of concept, but is not good code, and shall never be used in practice. This way, you won't have to deal with rewriting stdio.
If you know how to implement a int stack, you can create your own ungetc() function. Simply replace calls of ungetc() with a myungetc() (etc) that if that stack has values, pop them instead of reading from getc(). Whenever you want to un-get, simply push values on to the stack in the reverse order you read them.
An example from a recent project of mine:
/* stack.h */
#ifndef _STACK_H_
#define _STACK_H_
typedef struct {
int * vals;
int currsize;
int maxsize;
} stack;
int stack_init(stack * this, int size);
void stack_destroy(stack * this);
void push(stack * this, int val);
int pop(stack * this);
int isempty(stack * this);
int isfull(stack * this);
int size(stack * this);
int maxsize(stack * this);
#endif
/* stack.c */
#include <stdlib.h>
#include "stack.h"
#define THIS (this)
#define VALS (this->vals)
#define CURRSIZE (this->currsize)
#define MAXSIZE (this->maxsize)
int stack_init(stack * this, int size) {
VALS = malloc(sizeof(int)*size);
CURRSIZE = 0;
MAXSIZE = size;
if (!VALS) {
return 1; /* alloc fail */
}
return 0; /* successful init */
}
void stack_destroy(stack * this) {
free(VALS);
}
void push(stack * this, int val) {
if (isfull(THIS)) {
return;
}
VALS[CURRSIZE++] = val;
}
int pop(stack * this) {
if (isempty(THIS)) {
return 0;
}
return VALS[--CURRSIZE];
}
int isempty(stack * this) {
return (CURRSIZE == 0);
}
int isfull(stack * this) {
return (CURRSIZE == MAXSIZE);
}
int size(stack * this) {
return CURRSIZE;
}
int maxsize(stack * this) {
return MAXSIZE;
}
#undef THIS
#undef VALS
#undef CURRSIZE
#undef MAXSIZE
/* main.c */
#include <stdlib.h>
#include <stdio.h>
#include "stack.h"
int stgetc(FILE * stream, stack * pushed) { /* The getc() equivalent */
if (isempty(pushed)) {
return getc(stream);
} else {
return pop(pushed);
}
}
int stpush(int val, stack * pushed) { /* The ungetc() equivalent */
if (isfull(pushed)) {
return 1;
} else {
push(pushed,val);
return 0;
}
}
int main(int argc, char ** argv) {
/* startup code, etc. */
stack pushbuf; /* where the pushback will be stored */
stack_init(&pushbuf, 32) /* 32 = maximum number of ungetc calls/characters we can push */
FILE * in = fopen("/some/file","r");
/* file read */
int readchar;
while ((readchar = stgetc(in,pushbuf)) != EOF) {
/* do stuff */
stpush(readchar,pushbuf); /* oops, read too much! */
}
fclose(&in); /* close file */
stack_destroy(&pushbuf); /* clean up our buffer */
/* ... */
}
(I apologize for the wall of text but a shorter example isn't possible)
Considering you seem to be working with a file, it should be possible to fseek() backwards, although this will work for both files and stdin.

Setting byte array pointer in structure in C

I have a structure that contains a pointer to a byte array.
To set the pointer I’ve tried the following two ways:
1 Use malloc then memcpy byte array data (commented out in code below).
2 Simply copy pointer.
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
typedef struct _element
{
unsigned char *pValue;
int nLength;
} Element;
Element* ElementCreate(void)
{
Element *pElement = (Element*)malloc(sizeof(*pElement));
pElement->pValue = NULL;
pElement->nLength = 0;
return pElement;
}
void ElementDestroy(Element **ppElement)
{
Element *pElement = NULL;
if (!ppElement)
return;
pElement = *ppElement;
//free(pElement->pValue);
//pElement->pValue = NULL;
free(pElement);
*ppElement = NULL;
}
void ElementSetValue(Element *pElement, unsigned char *pValue, int nLength)
{
//pElement->pValue = (unsigned char*)malloc(nLength * sizeof(*(pElement->pValue)));
//if (!(pElement->pValue))
// return;
//memcpy(pElement->pValue, pValue, nLength);
pElement->pValue = pValue;
pElement->nLength = nLength;
}
void ElementWriteValue(const Element *pElement)
{
int nIndex = 0;
for (; nIndex < pElement->nLength; nIndex++)
printf("%02X ", pElement->pValue[nIndex]);
}
int main(void)
{
//unsigned char myValue[] = { 0x01, 0x02, 0x03 };
//int nLength = sizeof(myValue) / sizeof(myValue[0]);
Element *pElement = ElementCreate();
{
unsigned char myValue[] = { 0x01, 0x02, 0x03 };
int nLength = sizeof(myValue) / sizeof(myValue[0]);
ElementSetValue(pElement, myValue, nLength);
}
// How come this writes out correct value?
ElementWriteValue(pElement);
ElementDestroy(&pElement);
return 0;
}
(Error checks are omitted for brevity)
Which way is correct?
I’d expect 2 to fail because myValue will be destroyed after the “}” so
printf("%02X ", pElement->pValue[nIndex]);
would write out rubbish data but it seems to work OK. Why?
It is undefined behaviour, of which a subset is to "work correctly".
The array myValue is out of scope at the next }. At this point the memory location in which myValue was stored is available to be resused, but it may not be leaving it unchanged and hence the code appears to work.
The correct approach is to malloc(), memcpy() and free().
when we enter into
{
unsigned char myValue[] = { 0x01, 0x02, 0x03 };
int nLength = sizeof(myValue) / sizeof(myValue[0]);
ElementSetValue(pElement, myValue, nLength);
}
that mean a memory will be reserved for myValue. and when we leave it (after }) that mean the memory related to myValue is not reserved any more and it's free but the content is not changed. and that's why you have access to memory and its content is not changed.
If your application is multithread application then there is a big risk that the data related to myValue meory changes by another thread and in this case you have always access to the same memory space but you will find that the memory content changes

C Programming - Malloc Structs and undefined arrays

I am writing a program in C and I am trying to create these structs.
I have three of them:
the first consisting of 2 ints and 2 chars,
the second consisting of an int and an undefined array of pointers to the first one,
and a third which contains 4 longs and 2 ints along with an undefined array of pointers to the second.
I am having trouble I believe with memory allocation for these structs when instantiated. Does anyone know what I am doing wrong (code below). Cache_Simulator is the main class and uses the others. Any help appreciated.
Directory_block.c
#include <stdio.h>
#include <stdlib.h>
#include "Directory_Block.h"
/* Created September, 15th, 2010;
*
* Author: TJ, Cory
*/
char containsData(directory_block* checkMe){
return checkMe->valid;
}
void setValidOn(directory_block* checkMe){
checkMe->valid = 1;
}
void setValidOff(directory_block* checkMe){
checkMe->valid = 0;
}
char isOlder(directory_block* checkMe, int currentOldest){
if(currentOldest < checkMe->LRU){
return 1;
}
else{
return 0;
}
}
void setTag(directory_block* setMe, int tag){
setMe->tag = tag;
}
char matchesTag(directory_block* checkMe, int theirTag){
if(checkMe->tag == theirTag){
return 1;
}
else{
return 0;
}
}
void incrementLRU(directory_block* incrementMe){
incrementMe->LRU++;
}
void setLRU(directory_block* editMe, int LRUVal){
editMe->LRU = LRUVal;
}
cache_set* createSet(int setNumber,int numberOfBlocks,int printDetails){
cache_set* newSet = malloc(sizeof(cache_set) + sizeof(directory_block)*numberOfBlocks);
newSet->setNumber = setNumber;
printf("Making Set %d\n",newSet->setNumber);
int i = 0;
for(; i < numberOfBlocks;i++)
{
printf("\tMaking Block #%d ",i);
if((i%4)==0&&i!=0)
{
printf("\n");
}
directory_block* block = malloc(sizeof(directory_block));
newSet->blocks[i] = block;
setValidOff(newSet->blocks[i]);
setTag(newSet->blocks[i],setNumber);
setLRU(newSet->blocks[i],-1);
if(printDetails == 1)
{
printf("\tAddress %d\n",(int)newSet->blocks[i]);
printf("\t\tValid=%d\n\t\tLRU=%d\n\t\tTag=%d\n",newSet->blocks[i]->valid
,newSet->blocks[i]->LRU,newSet->blocks[i]->tag);
}
}
printf("\n");
return newSet;
}
Directory_block.h
#ifndef DIRECTORY_BLOCK_H_
#define DIRECTORY_BLOCK_H_
#include "Directory_Block.h"
struct directory_block;
struct set;
struct cache;
typedef struct{
int tag;
int LRU;
char valid;
char offset;
}directory_block;
typedef struct{
int setNumber;
directory_block* blocks[];
}cache_set;
typedef struct{
int numberOfSets;
int linesPerSet;
long hits;
long misses;
long unknownAccesses;
long flushes;
cache_set* sets[];
}cache;
/*
* params: checkMe - the line of the cache that we are checking
* return: true = valid == 1; false valid == 0
*/
char containsData(directory_block* checkMe);
/*
* functions: to set the valid bit to 1
*/
void setValidOn(directory_block* checkMe);
/*
* functions: to set the valid bit to 0
*/
void setValidOff(directory_block* checkMe);
/*
* params: currentOldest - the current oldest in directory_block*
* return: the oldest current directory_block*
*/
char isOlder(directory_block* checkMe, int currentOldest);
/*
* params: theirTag - the tag that is in the directory_block*
* return: 0 if false; 1 is true
*/
char matchesTag(directory_block* checkMe, int theirTag);
/*
* function: increments the value of the LRU in the block
*/
void incrementLRU(directory_block* incrementMe);
void setTag(directory_block* setMe, int tag);
/*
* param: LRUVal - value to set to LRU to (negative means hasn't been used)
*/
void setLRU(directory_block* editMe,int LRUVal);
/*
* param: numberOfBlocks number of blocks per set
* creates a set and instantiates all directory blocks;
* param: setNumber number of this set in the cache
*/
cache_set* createSet(int setNumber,int numberOfBlocks,int details);
#endif /* DIRECTORY_BLOCK_H_ */
Cache.c
#include "Directory_Block.h"
#include <stdio.h>
#include <stdlib.h>
directory_block* findLRU(cache* checkMe,int index){
int age;
age = 0;
int i = 0;
int oldest = 0;
for(; i < checkMe->numberOfSets;i++)
{
if(isOlder(checkMe->sets[i]->blocks[index],age) == 1)
{
oldest = i;
age = checkMe->sets[i]->blocks[index]->LRU;
}
}
return checkMe->sets[i]->blocks[i];
}
int readInAddress(cache checkMe,char fileName[]){
return 0;
}
cache *makeCache(int numberOfLines,int numberOfSets,int details){
cache* returnMe = (cache*)malloc(sizeof(cache) + sizeof(int)*numberOfSets);
returnMe->numberOfSets = numberOfSets;
returnMe->linesPerSet = numberOfLines;
printf("Making Cache\n");
int i=1;
for(; i < returnMe->numberOfSets;i++){
returnMe->sets[i] = createSet(i,returnMe->linesPerSet,details);
}
return returnMe;
}
void writeToCache(cache *addToMe,int address,int tag,int offset)
{
directory_block* LRUblock = findLRU(addToMe,address);
LRUblock->LRU = 0;
LRUblock->tag = tag;
LRUblock->valid = 1;
LRUblock->offset = offset;
}
char processAddress(cache checkMe,int address){
return 0;
}
void reportCacheStatus(cache *reportMe){
int i = 0;
int j = 0;
for(;i < reportMe->numberOfSets;i++)
{
printf("Set #%d\n",i);
for(j=0;j < reportMe->linesPerSet;j++)
{
printf("\tBlock #%d - Tag=%d Valid=%d LRU=%d Offset=%d\n",j,reportMe->sets[i]->blocks[j]->tag
,reportMe->sets[i]->blocks[j]->valid,reportMe->sets[i]->blocks[j]->LRU
,reportMe->sets[i]->blocks[j]->offset);
}
}
}
Cache.h
#include "Set.h"
#ifndef CACHE_H_
#define CACHE_H_
/*
* params: checkMe - cache which that we will look for LRU at
* index - line index which we will check for LRU in all sets
* return: setIndex - of the LRU block
* function - iterates through sets and compares LRU value of directory_block at given
* index for each set.
*
*/
int findLRU(cache checkMe,int index);
/*
* params: char [] - Name of File to read
* return address struct contains access type and parsed address
*/
int readInAddress(cache checkMe,char[]);
/*
*params: int cacheSize total bytes in cache, int linesPerSet number of blocks per set
*params: int lineSize number of bytes per line
* return int [] pointer with # of fields
* (DEFINE FIELDS)
*/
cache* makeCache(int numberOfLines,int numberOfSets,int details);
/*
* params: int address - perform cpu call for that address and see if there is a
* hit or miss or unknown access type - Update stats
*/
char processAddress(cache checkMe,int address);
void writeToCache(cache *addToMe,int address);
/*
*Prints out display of information
*For passes cache
*Ex.
* INSERT EXAMPLE LINE
*/
void reportCacheStatus(cache* reportMe,int numberOfSets,int blocksPerSet);
#endif /* CACHE_H_ */
Cache_simulator.c
#include <stdio.h>
#include <stdlib.h>
#include "fileParser.h"
#include "Directory_Block.h"
#include "Cache.h"
void setupCache(int details);
void performTrace(void);
void report(void);
int main(void)
{
printf("The Cache Simulator:\n\tJonathan Katon\n\tCory Brett\n\tThomas Pavlu\n");
setupCache(1);
//performTrace();
report();
return 0;
}
void setupCache(int details)
{
int numberOfLines = 1024/1;
int numberOfSets = numberOfLines/4;
numberOfLines = numberOfLines/numberOfSets;
printf("Number of Sets %d \nNumber of Lines Per Set %d\n",numberOfSets,numberOfLines);
printf("Cache Size %d,Cache_Set Size %d,Directory_block Size %d",sizeof(cache),sizeof(cache_set),sizeof(directory_block));
cache *instructionCache = makeCache(numberOfLines,numberOfSets,details);
//writeToCache(instructionCache,0);
reportCacheStatus(instructionCache,numberOfSets,numberOfLines);
}
void performTrace(void)
{
FILE* trace;
trace = fopen("trace.txt","r");
readNextMemoryAccess(trace);
}
void report(void)
{ // T.B.D
}
From an 'answer' by the OP about the question:
This was my attempt to try and fix a problem I was having with the memory at least i think I was. When I do a sizeof(cache_set) only it only returns a size large enough for everything but the array of pointers. This makes sense because the array isn't finite my question is how do I get around this issue? Any suggestions. Oh, and by the way, thanks for taking at look at this.
in Directory_block.c
cache_set* newSet = malloc(sizeof(cache_set) + sizeof(directory_block)*numberOfBlocks);
newSet is a pointer with space for:
1 cache_set: ok
numberOfBlocks directory_blocks: huh?
This is wrong: cache_sets do not have directory_blocks in them; they have pointers to directory_blocks
typedef struct{
int setNumber;
directory_block* blocks[];
}cache_set;
I'd pay great attention to your type structure. Do you really need an array of pointers to directory_blocks inside cache_sets? If you do, the typedef is ok; if you don't, it's (probably) the code that's ok ... but, anyway, ... the structure and the malloc don't match.
Edit use the flexible array member
Suppose we have a struct with a flexible array member
struct Example {
int value;
double fam[]; /* fam is the flexible array, of doubles */
};
and now we want to use a variable of type struct Example with space for 100 doubles:
struct Example *example;
example = malloc(sizeof *example + 100 * sizeof *example->fam);
if (example) {
/* use example, eg: */
example->fam[42] = 3.14159265;
/* and remember to free the allocated object when done */
free(example);
}

Resources