I create a buffer via this function.
int create_buffer(const char *shmem_name, void **shmem_obj)
{
int returnval = 0;
int fd;
fd = shm_open(shmem_name, O_CREAT | O_RDWR, 0666);
ftruncate(fd, sizeof(ShareStruct));
*shmem_obj = (ShareStruct *)mmap(NULL, sizeof(ShareStruct), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shmem_obj < 0)
{
returnval = -1;
}
return returnval;
}
Then when I use the pointer in process 1 and its functions, everything works.
In process 2 I fetch the buffer using this function:
int fetch_buffer(const char *shmem_name, void **shmem_obj)
{
int returnval = 0;
int fd;
fd = shm_open(shmem_name, O_RDWR, 0666);
ftruncate(fd, sizeof(ShareStruct));
*shmem_obj = (ShareStruct *)mmap(NULL, sizeof(ShareStruct), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shmem_obj < 0)
{
returnval = -1;
}
printf("buffer fetched \n");
return returnval;
}
But the contents of the buffer are different (weird values).
What am I doing wrong?
EDIT:
process 1 code:
#define SHMEM_NAME "OS"
int main(void) {
int exitcode = 0;
void *shmem_obj;
/* Initialize the buffer and create the shared memory */
if( create_buffer(SHMEM_NAME, &shmem_obj) != 0) {
fprintf(stderr, "Something went wrong while initializing the buffer.\n");
exitcode = 1;
} else {
printf("Shared buffer created.\n");
initParameters(&shmem_obj);
subscribe(0, &shmem_obj);
printf("\n[PRESS ENTER TO CLOSE THE SHARED BUFFER]");
getchar();
/* unlink the shared memory */
if(destroy_buffer(SHMEM_NAME) != 0) {
fprintf(stderr, "Something went wrong while destroying the buffer.\n");
exitcode = 2;
} else {
printf("Shared buffer closed.\n");
}
}
return exitcode;
}
Process 2 code:
#define SHMEM_NAME "OS"
int main(void) {
void *shmem_obj;
/* fetch the buffer from shared memory */
fetch_buffer(SHMEM_NAME, &shmem_obj);
subscribe(1, &shmem_obj);
printf("Subscriber 0 subscribed\n");
}
Other code:
typedef struct ShareStruct
{
Subscriber subscriberList[20];
int subscriberActiveList[20];
unsigned int writepointer_tail;
unsigned int readpointer_head;
Task taskList[21];
sem_t freePostions;
pthread_mutex_t mutex;
unsigned int subscriberCount;
} ShareStruct;
int initParameters(void *shmem_obj)
{
ShareStruct *shmem = shmem_obj;
int returnval = 0;
shmem->writepointer_tail = 0;
shmem->readpointer_head = 0;
shmem->subscriberCount = 0;
pthread_mutex_init(&shmem->mutex, NULL);
sem_init(&shmem->freePostions, 1, 20);
return returnval;
}
int destroy_buffer(const char *shmem_name)
{
int returnval = 0;
returnval = shm_unlink(shmem_name);
return returnval;
}
int subscribe(subscriber_id subscriber, void *shmem_obj)
{
int returnval = 0;
ShareStruct *shmem = shmem_obj;
int value;
sem_getvalue(&shmem->freePostions, &value);
printf("sem value : %d\n", value);
pthread_mutex_lock(&shmem->mutex);
int freeposition = returnNextFreePosition(shmem_obj);
if (freeposition != -1)
{
printf("subscribe logic");
}
else
{
printf("Subscriber list is full \n");
}
pthread_mutex_unlock(&shmem->mutex);
return returnval;
}
The problem is that you're being inconsistent in the number of layers of pointer indirection there are, and your use of void * rather than more specific pointer types is preventing the compiler from realizing and telling you that you're doing that. Replace all of your void *s with ShareStruct *s, and then fix the resulting errors and warnings your compiler gives you, and your code will start to work.
Related
I'm trying to write a program that uses counting semaphores, a mutex, and two threads. One thread is a producer that writes items to shared memory. Each item has a sequence number, timestamp, checksum, and some data. The consumer thread copies the original checksum from an item then calculates its own checksum from the item's data and compares the two to make sure the data wasn't corrupted.
My program runs, however, it reports incorrect checksums far more than correct checksums. I did some print statements to see what was going on, and it looks like the item's data is changing between writing to shared memory and reading from it. The item's stored checksum is also changing, and I have no idea what is causing this.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <errno.h>
#include <stdint.h>
#include <semaphore.h>
#include <time.h>
#include <pthread.h>
typedef struct{
int seqNo;
uint16_t checksum;
uint32_t timeStamp;
uint8_t data[22];
}Item;
char* shm_name = "buffer";
int shm_fd;
uint8_t *shm_ptr;
pthread_t producers;
pthread_t consumers;
pthread_mutex_t mutex;
sem_t *empty, *full;
int shmSize;
int in = 0;
int out = 0;
//method for initializing shared memory
void CreateSharedMemory(){
shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0644);
if (shm_fd == -1) {
fprintf(stderr, "Error unable to create shared memory, '%s, errno = %d (%s)\n", shm_name,
errno, strerror(errno));
return -1;
}
/* configure the size of the shared memory segment */
if (ftruncate(shm_fd, shmSize) == -1) {
fprintf(stderr, "Error configure create shared memory, '%s, errno = %d (%s)\n", shm_name,
errno, strerror(errno));
shm_unlink(shm_name);
return -1;
}
printf("shared memory create success, shm_fd = %d\n", shm_fd);
}
uint16_t checksum(char *addr, uint32_t count)
{
register uint32_t sum = 0;
uint16_t *buf = (uint16_t *) addr;
// Main summing loop
while(count > 1)
{
sum = sum + *(buf)++;
count = count - 2;
}
// Add left-over byte, if any
if (count > 0)
sum = sum + *addr;
// Fold 32-bit sum to 16 bits
while (sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
return(~sum);
}
Item CreateItem(){
Item item;
uint16_t cksum;
int j = 0;
time_t seconds;
seconds = time(NULL);
item.seqNo = j;
item.timeStamp = seconds; //FIX this
for(int i = 0; i < 22; ++i){
item.data[i] = rand() % 256;
}
cksum = checksum(&item.data[0], shmSize-2);
item.checksum = cksum;
++j;
return item;
}
void* producer() {
shm_fd = shm_open(shm_name, O_RDWR, 0644);
shm_ptr = (uint8_t *)mmap(0, 32, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
while(1) {
Item tempItem = CreateItem();
tempItem.seqNo = in;
sem_wait(empty);
pthread_mutex_lock(&mutex);
while (((in + 1)%shmSize) == out)
; // waiting
if(in < shmSize) {
//&shm_ptr[counter] = item;
\
memcpy(&shm_ptr[in], &tempItem, 32);
printf("%d\n", tempItem.seqNo);
in = (in + 1) % shmSize;
printf("Producer: %x\n", tempItem.checksum);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sem_post(full);
}
}
void* consumer() {
uint16_t cksum1, cksum2;
shm_fd = shm_open(shm_name, O_RDWR, 0644);
shm_ptr = (uint8_t *)mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
while(1) {
sem_wait(full);
pthread_mutex_lock(&mutex);
while (in == out)
; // waiting
if(out > 0) {
Item tempItem;
memcpy(&tempItem, &shm_ptr[out], 32);
cksum1 = tempItem.checksum;
cksum2 = checksum(&tempItem.data[0], shmSize-2);
if (cksum1 != cksum2) {
printf("Checksum mismatch: expected %02x, received %02x \n", cksum2, cksum1);
}
else{
printf("removed from shm\n");
}
//printf("Checksums match !!! \n");
out = (out + 1)%shmSize;
}
sleep(1);
pthread_mutex_unlock(&mutex);
sem_post(empty);
}
}
int main(int argc, char **argv){
sem_unlink(&empty);
sem_unlink(&full);
shm_unlink(shm_name);
shmSize = atoi(argv[1]);
out = shmSize;
if(shmSize < 0){
printf("Error: Size of buffer cannot be negative. ");
return -1;
}
pthread_mutex_init(&mutex, NULL);
empty = sem_open("/empty", O_CREAT, 0644, shmSize);
full = sem_open("/full", O_CREAT, 0644, 0);
CreateSharedMemory();
pthread_create(&producers, NULL, producer, NULL);
pthread_create(&consumers, NULL, consumer, NULL);
pthread_exit(NULL);
Driver's mmap() entry point not getting called.
This is the source code of my device driver:
struct miscdevice my_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mymma",
.fops = &my_fops,
};
static const struct file_operations my_fops = {
.owner = THIS_MODULE,
.mmap = my_mmap,
};
static int __init my_module_init(void)
{
return my_init();
}
static void __exit my_module_exit(void)
{
my_exit();
}
int my_init(void)
{
int ret =0;
if ((ret = misc_register(&my_dev)))
{
printk(KERN_ERR "Unable to register \"my mma\" misc device\n");
return ret;
}
printk("kernel module installed\n");
return ret;
}
But my driver's mmap() entry point is not getting called.
This is the user space program calling it:
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
int main(){
int fd=open("/dev/mymma",O_RDONLY);
if(fd<0)
exit(0);
printf("helllo\n");
int N=5;
int *ptr = mmap ( NULL, N*sizeof(int),
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0 );
if(ptr == MAP_FAILED){
printf("Mapping Failed\n");
return 1;
}
for(int i=0; i<N; i++)
ptr[i] = i*10;
for(int i=0; i<N; i++)
printf("[%d] ",ptr[i]);
printf("\n");
int err = munmap(ptr, 10*sizeof(int));
if(err != 0){
printf("UnMapping Failed\n");
return 1;
}
return 0;
}
Provide the mmap() entry point of your driver.
I can notice that the device node is opened RDONLY but you are calling mmap() with PROT_READ/WRITE. Moreover MAP_ANONYMOUS makes mmap() ignore the file descriptor: you are merely allocating some space in memory. That is why you don't reach your driver.
I was working on a C programming database tutorial (linked here- https://www.youtube.com/watch?v=SEenaPQXxFs )
When I go to run my code and insert new data into the database it does generate a data file, but no data is stored in the data file/database at all- im not really sure why its not working, and as far as I can tell no errors populate.
The code I was working on is as follows
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
//give structure to record
typedef struct
{
unsigned int key; //primary key assingment
char fname[16]; // defines length allowed for names
char lname[16]; //same but for last name
unsigned int age;
} person_rec; //gives name to definition
int open_record(char *filename) //function to open record
{
int fd;
fd = open(filename, O_CREAT | O_APPEND, 0644);
if(fd == -1)
perror("open_record");
return fd;
}
void close_record(int fd) //close record
{
close(fd);
}
int insert_record(int fd, person_rec *rec) //unkkown
{
int ret;
ret = write(fd, rec, sizeof(person_rec));
return ret;
}
//function to delete and print
int get_record(int fd, person_rec *rec, int key)
{
int ret;
while( ( ret = read(fd, rec, sizeof(person_rec)) ) != -1)
{
if(ret == 0)
{
memset(rec, 0, sizeof(person_rec)); //clear any errors by resetting size
break;
return ret;
}
else if (key == rec->key)
return ret;
}
memset(rec, 0, sizeof(person_rec)); //clear record if error due to -1 size
return ret;
}
//delete function
int delete_record(int fd, int key)
{
int ret;
person_rec rec;
off_t pos;
pos = lseek(fd, 0, SEEK_SET);
while( ( ret = read(fd, &rec, sizeof(person_rec)) ) != -1)
{
if(ret == 0)
{
return ret;
}
else if (key == rec.key)
{
lseek(fd, pos, SEEK_SET);
rec.key = 0;
ret = write(fd, &rec, sizeof(person_rec));
return ret;
}
pos = lseek(fd, 0, SEEK_CUR);
}
return ret;
}
int main(int argc, char *argv[]) //main function/uses all prior defined function to make database ect
{
int fd;
person_rec rec;
fd = open_record("data1");
if(argc > 1)
{
/* insert */
if(argc > 5 && !strcmp(argv[1], "insert"))
{
rec.key = atoi(argv[2]);
strcpy(rec.fname, argv[3]);
strcpy(rec.lname, argv[4]);
rec.age = atoi(argv[5]);
insert_record(fd, &rec);
}
/* delete */
if(argc > 2 && !strcmp(argv[1], "delete"))
delete_record(fd, atoi(argv[2]));
/*print */
if(argc > 2 && !strcmp(argv[1], "print"))
{
get_record(fd, &rec, atoi(argv[2]));
printf("key = %d\n", rec.key);
printf("First = %s\n", rec.fname);
printf("Last = %s\n", rec.lname);
printf("Age = %d\n", rec.age);
}
}
return 0;
}
From the open man page:
The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR.
So:
fd = open(filename, O_CREAT | O_APPEND, 0644);
should be:
fd = open(filename, O_CREAT | O_APPEND | O_RDWR, 0644);
I don't see any call to fclose() or fflush() to empty buffer to disk. Add fflush() after every write or fclose() before exiting the program.
I am currently working on a producer-consumer implementation using C.
First, I create a buffer on the shared memory of a variable length that is given by the user in the consumer process.
Then, in the producer process, I need to access the shared memory and puts new data to the buffer so the consumer can consume.
Below is the consumer code:
#include "common.h"
#include <unistd.h>
int fd;
int errno;
int MY_LEN = 0;
Shared* shared_mem;
char *job[4];
int setup_shared_memory(){
fd = shm_open(MY_SHM, O_CREAT | O_RDWR, 0666);
if(fd == -1){
printf("shm_open() failed\n");
exit(1);
}
ftruncate(fd, sizeof(Shared) + MY_LEN*sizeof(char *));
}
int attach_shared_memory(){
shared_mem = (Shared*) mmap(NULL, sizeof(Shared) + MY_LEN*sizeof(char *), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shared_mem == MAP_FAILED){
printf("mmap() failed\n");
exit(1);
}
return 0;
}
int init_shared_memory() {
shared_mem->data = 0;
int i;
for(i = 0; i < shared_mem->length; i++)
{
shared_mem->arr[i] = 0;
// shared_mem->arr[i] = (char *)calloc(1, sizeof(char*));
}
sem_init(&(shared_mem->mutex), 1, 1);
}
int init_job(){
int i;
for(i = 0; i < 4; i++)
{
job[i] = (char *)malloc(sizeof(char *));
}
}
int take_a_job(int index){
init_job();
char *ds = strdup(shared_mem->arr[index]);
job[0] = strtok(ds, "-");
int i = 1;
while(i < 4)
{
job[i] = strtok(NULL, "-");
i++;
}
// remove the job from the buffer
shared_mem->arr[index] = NULL;
}
int consume_job(int index){
printf("\nPrinter starts printing the job %s, %s pages from Buffer[%d]. The duration is %s seconds and the source is %s.\n",job[3], job[2], index, job[1], job[0]);
sleep(atoi(job[1])); // sleep for job[1] seconds.
}
int main(int args, char *argv[]) {
setup_shared_memory();
attach_shared_memory();
init_shared_memory();
MY_LEN = atoi(argv[1]); // the first parameter following ./printer = the length of the buffer
shared_mem->length = MY_LEN;
//shared_mem->arr = (int*) &shared_mem->arr;
int index = 1;
*(shared_mem->arr) = "1-10-5-6";
*(shared_mem->arr + 1) = "2-5-2-7";
*(shared_mem->arr + 2) = "3-20-10-8";
*(shared_mem->arr + 3) = "4-7-4-9";
take_a_job(index);
int i;
for(i = 0; i < shared_mem->length; i++){
printf("\n\n%d set %s\n", i, shared_mem->arr[i]);
}
consume_job(index);
printf("\n\nHello second check\n\n");
while (1) {}
return 0;
}
Here is the producer code:
#include "common.h"
int fd;
Shared* shared_mem;
char *job;
int setup_shared_memory(){
fd = shm_open(MY_SHM, O_RDWR, 0666);
if(fd == -1){
printf("shm_open() failed\n");
exit(1);
}
}
int attach_shared_memory(){
shared_mem = (Shared*) mmap(NULL, sizeof(Shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shared_mem == MAP_FAILED){
printf("mmap() failed\n");
exit(1);
}
return 0;
}
int create_a_job(int args, char *argv[]){
int i;
job = (char *)calloc(8, sizeof(char *));
if(args != 5)
return 0; //the parameters are not correctly formatted
else{
for(i = 1; i < args; i++)
{
if(i > 1)
strcat(job, "-");
strcat(job, argv[i]);
}
}
strcat(job, "\0");
printf("\nthe job is %s\n", job);
}
int put_a_job(){
printf("shared_mem->length is %d\n\n", shared_mem->length);
int i;
for(i = 0; i < shared_mem->length; i++)
{
if(*(shared_mem->arr + i) == 0)
{
//shared_mem->arr[i] = (char *)malloc(sizeof(job));
//strcpy(shared_mem->arr[i], job);
*(shared_mem->arr + i) = (char *)job;
printf("\n\nThe index is %d\n", i);
//printf("\n\nthe argument is %s at %d\n", job, i);
return i;
}
}
printf("\n\nThe index is %d\n", i);
}
int main(int args, char *argv[]) {
setup_shared_memory();
attach_shared_memory();
// create a job with the parameters
int result = create_a_job(args, argv);
if(result == 0)
{
printf("Not the right parameters.\n");
printf("Plase enter client ID, job duration, number of pages and job ID.\n");
return 0;
}
int i;
put_a_job();
for (i=0; i < shared_mem->length; i++) {
printf("the argument is %s at %d\n", (char *)(shared_mem->arr + i), i);
}
printf("\n\n");
return 0;
}
The common.h file is
#ifndef _INCLUDE_COMMON_H_
#define _INCLUDE_COMMON_H_
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
// from `man shm_open`
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <string.h>
#include <semaphore.h>
#define MY_SHM "/JIT"
typedef struct {
sem_t mutex;
int data;
int length; // the length of the buffer
char *arr[0];
} Shared;
#endif //_INCLUDE_COMMON_H_
I first run ./consumer 10 & to allocate a buffer of length 10 and after, I run ./producer 1 2 3 4 to put the job to the buffer and print the buffer, I got garbage values
Any help would be really appreciated! Thank you!
Instruction
*(shared_mem->arr + i) = (char *)job;
is storing the pointer job into the shared mem, not the pointed value.
Maybe you want to use a strncpy.
You cannot share memory address between processes, because of Linux uses virtual memory. To make the story short an address in a process is not valid for a different process.
Be aware that you have a memory leakage because you never call free() for the allocated job.
I have write this code but i have a problem
first i have a function that create a file descriptor (fd)
int fd;//global
static int init_fd(int fd) {
remove("file descriptor.txt");//if yet present
fd = open("file descriptor.txt", O_WRONLY | O_CREAT, 0666);
if (fd == -1) {
printf("Error in opening the file descriptor!\n");
exit(0);
}
return fd;
}
the second function is a handler function
static int handler(struct connection *conn, enum event ev) {
...
int i;
for (i = 0; i < array_size; i++) {
if (!strncmp(conn->uri, uri_array[i], strlen(uri_array[i]))) {
func_array[i](conn->request_method, conn->uri, NULL, init_fd(fd));
close(fd);
fd = open("file descriptor.txt", O_RDONLY);
ret = read(fd, &buf, BUFSIZ);
if (ret == -1) {
printf("Error in reading!\n");
exit(0);
}
...
}
with fun_array is a pointer to function
httpCallback_t func_array[MAXARRAY];
and the function is
void http_serve1(const char *method, const char *path, const httpOptions_t *options, int fd) {
const char *string = "All is ok1!";
int ret_value;
// send header: 200 OK
ret_value = sendHeaders(fd, TIMEOUT_SEC, NETHTTP_HTTP_HEADER_200, NETHTTP_Content_Type_text_html_utf8, NETHTTP_CRLF, NULL);
// close the file descriptor
close(fd);
}
and the function sendHeaders is
size_t sendHeaders(int fd, int seconds, const char* header1, ...) {
va_list args;
va_start(args, header1);
size_t totalSize = 0;
const char* hdr = header1;
while (hdr != NULL) {
size_t result = sendHeaders(fd, seconds, hdr, NULL); // segmentation fault
if (result < 0) {
return result;
}
totalSize += result;
hdr = va_arg(args, const char*);
va_end(args);
return totalSize;
}
if (size == SIZE) {
setErrorCode(ERROR);
return ERROR;
}
size_t sizewrite = 1024;
tmp[size] = strdup(hdr);
write(fd, tmp, sizewrite);
setErrorCode(SUCCESS);
return SUCCESS;
}
my problem is that my code create a file descriptor, but it doesn't write inside, and during the run i have problem with segmentation fault. anyone have a suggest?