I am using Shared memory (POSIX), to share a FILE pointer(FILE * rt_file), but it's not getting file pointer at client end. Any suggestions please.
/*
* shm_msgserver.c
*
* Illustrates memory mapping and persistency, with POSIX objects.
* This process produces a message leaving it in a shared segment.
* The segment is mapped in a persistent object meant to be subsequently
* open by a shared memory "client".
*
*
* Created by Mij <mij#bitchx.it> on 27/08/05.
* Original source file available at http://mij.oltrelinux.com/devel/unixprg/
*
*/
#include <stdio.h>
/* shm_* stuff, and mmap() */
#include <sys/mman.h>
#include <sys/types.h>
/* exit() etc */
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
/* for random() stuff */
#include <stdlib.h>
#include <time.h>
/* Posix IPC object name [system dependant] - see
http://mij.oltrelinux.com/devel/unixprg/index2.html#ipc__posix_objects */
#define SHMOBJ_PATH "/foo1423"
/* maximum length of the content of the message */
#define MAX_MSG_LENGTH 50
/* how many types of messages we recognize (fantasy) */
#define TYPES 8
/* message structure for messages in the shared segment */
struct msg_s {
int type;
char content[MAX_MSG_LENGTH];
FILE *pt;
};
int main(int argc, char *argv[]) {
int shmfd;
int shared_seg_size = (1 * sizeof(struct msg_s)); /* want shared segment capable of storing 1 message */
struct msg_s *shared_msg; /* the shared segment, and head of the messages list */
FILE *rt_file;
rt_file = fopen ("res","a+");
printf("rt_file : %s\n",rt_file);
/* creating the shared memory object -- shm_open() */
shmfd = shm_open(SHMOBJ_PATH, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
fprintf(stderr, "Created shared memory object %s\n", SHMOBJ_PATH);
/* adjusting mapped file size (make room for the whole segment to map) -- ftruncate() */
ftruncate(shmfd, shared_seg_size);
/* requesting the shared segment -- mmap() */
shared_msg = (struct msg_s *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if (shared_msg == NULL) {
perror("In mmap()");
exit(1);
}
fprintf(stderr, "Shared memory segment allocated correctly (%d bytes).\n", shared_seg_size);
srandom(time(NULL));
/* producing a message on the shared segment */
shared_msg->type = random() % TYPES;
snprintf(shared_msg->content, MAX_MSG_LENGTH, "My message, type %d, num %ld", shared_msg->type, random());
shared_msg->pt = rt_file;
/* [uncomment if you wish] requesting the removal of the shm object -- shm_unlink() */
/*
if (shm_unlink(SHMOBJ_PATH) != 0) {
perror("In shm_unlink()");
exit(1);
}
*/
return 0;
}
Client Code
/*
* shm_msgclient.c
* http://mij.oltrelinux.com/devel/unixprg/#ipc__posix_shm
* Illustrates memory mapping and persistency, with POSIX objects.
* This process reads and displays a message left it in "memory segment
* image", a file been mapped from a memory segment.
*
*
* Created by Mij <mij#bitchx.it> on 27/08/05.
* Original source file available at http://mij.oltrelinux.com/devel/unixprg/
*
*/
#include <stdio.h>
/* exit() etc */
#include <unistd.h>
/* shm_* stuff, and mmap() */
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
/* for random() stuff */
#include <stdlib.h>
#include <time.h>
/* Posix IPC object name [system dependant] - see
http://mij.oltrelinux.com/devel/unixprg/index2.html#ipc__posix_objects */
#define SHMOBJ_PATH "/foo1423"
/* maximum length of the content of the message */
#define MAX_MSG_LENGTH 50
/* how many types of messages we recognize (fantasy) */
#define TYPES 8
/* message structure for messages in the shared segment */
struct msg_s {
int type;
char content[MAX_MSG_LENGTH];
FILE *pt;
};
int main(int argc, char *argv[]) {
int shmfd;
int shared_seg_size = (1 * sizeof(struct msg_s)); /* want shared segment capable of storing 1 message */
struct msg_s *shared_msg; /* the shared segment, and head of the messages list */
FILE *rt_file;
/* creating the shared memory object -- shm_open() */
shmfd = shm_open(SHMOBJ_PATH, O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
printf("Created shared memory object %s\n", SHMOBJ_PATH);
/* requesting the shared segment -- mmap() */
shared_msg = (struct msg_s *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if (shared_msg == NULL) {
perror("In mmap()");
exit(1);
}
printf("Shared memory segment allocated correctly (%d bytes).\n", shared_seg_size);
rt_file = shared_msg->pt;
printf("rt_file : %s\n",rt_file);
rt_file = fopen ("res","a+");
printf("rt_file : %s\n", rt_file);
char x[10]="ABCDEFGHIJ";
fwrite(x, sizeof(x[0]), sizeof(x)/sizeof(x[0]), rt_file);
printf("Message type is %d, content is: %s\n", shared_msg->type, shared_msg->content);
if(shm_unlink(SHMOBJ_PATH) == -1){
printf("%s is used by another Process\n",SHMOBJ_PATH);
}
else{
printf("Memory is freed\n");
}
return 0;
}
FILE* pointers are valid only in the process where they were created.
While you can transfer the pointer value, or even the structure it points to, to another process, using it in the other process will invoke undefined behaviour.
If you want another process on the same machine to access a certain file I suggest that you send the file name, mode and offset to the other process and let it create it's own FILE* structure by calling fopen.
Related
I am a complete rookie to programming in C and have been trying to program a system that will take an integer input, perform a calculation, and tack them onto a string that will then be passed to a shared memory. Apologies if I am being an idiot but I am getting an error about an incompatible pointer type. I dont know how I can fix this error.
Edit: I apologize for the bad initial question. Full code is included
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
/* The size (in bytes) of shared-memory object */
const int SIZE = 4096;
/* The name of shared-memory object */
const char *Obj = "Shm";
/* The shared-memory file descriptor */
int shm_fd;
/* The pointer to shared-memory object */
void *ptr;
/* Create the shared-memory object */
shm_fd = shm_open(Obj, O_CREAT | O_RDWR, 0666);
/* Configure the size of the shared-memory object */
ftruncate(shm_fd, SIZE);
/* Map the shared-memory object in the address space of the process */
ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED)
{
printf("Map failed\n");
return -1;
}
int cal;
char newStr[200];
char currentStr[200];
char *temp;
char value;
printf("Enter an integer");
scanf("%d", &cal);
/* Create a message and write it to the shared-memory object */
/*fgets(ptr, SIZE, stdin);*/
if (cal == 0) {
printf("0 is not valid");
return -1;
}
if (cal < 1) {
printf("Please enter a positive int");
return -1;
}
sprintf(newStr, "%d", cal);
while (cal != 1) {
if (cal % 2 == 0) {
cal = cal / 2;
}
else {
cal = 3 * cal + 1;
}
value = cal + '0';
sprintf(currentStr, " --- %d", value);
strcat(newStr, currentStr);
}
fgets(ptr, SIZE, newStr);
printf("Writing the message to the shared memory is done! \n");
return 0;
}
Due to nature of my coding environment testing and figuring out the exact nature of errors is particularly difficult.
Edit: Here is the exact error message
Collatz-Producer.c:84:2: warning: passing argument 3 of ‘fgets’ from incompatible pointer type [enabled by default]
And I had cut out the section above with ptr since I was confident it worked, though here is the specifics of what ptr equals
void *ptr;
ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
According to this documentation, the function fgets takes 3 parameters, in this order:
a pointer to the memory buffer to write to
the size of the memory buffer
the FILE * stream to read from, for example stdin
The array newStr is not a FILE * stream. Therefore, it is not valid as a third parameter.
If you do not intend to read from a FILE * stream (such as stdin or a file opened with fopen), then you should not be using the function fgets.
I am writing a simple application on C that uses shared memory but I cannot run it anymore as it says:
shmat: Cannot allocate memory
I am using this script to free my memory but doesn't seem to work.
This is a screenshot of my processes:
This is the application code:
/* Shared Memory IPC creates a mamory space and send contendt to it while the other process can read from it.
Our implementation works like this:
1. First run the application by passing as a argument the value you want to send to the shared memory. Example: ./ipc_sharedmem.o 4
2. Run the appliation again to read from the shared memory (which is a new process, of course) wihout sending any arguments. Exmaple: ./ipc_sharedmem.o
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 1024 /* make it a 1K shared memory segment */
int main(int argc, char *argv[])
{
key_t key;
int shared_mem_mid;
char *data;
struct timeval t1, t2, t3, t4;
if (argc > 2) {
fprintf(stderr, "usage: shmdemo [data_to_write]\n");
exit(1);
}
/* make the key: */
if ((key = ftok("mach.c", 'R')) == -1) {
perror("ftok");
exit(1);
}
/* connect to (and possibly create) the segment: */
if ((shared_mem_mid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) {
perror("shmget");
exit(1);
}
/* attach to the segment to get a pointer to it: */
gettimeofday(&t1, NULL);
data = (char *) shmat(shared_mem_mid, (void *)0, 0);
gettimeofday(&t2, NULL);
if (data == (char *)(-1)) {
perror("shmat");
exit(1);
}
printf("Time to read the message from sharem memory: %g \n", (t2.tv_sec + t2.tv_usec/1000000.0)-(t1.tv_sec + t1.tv_usec/1000000.0));
/* read or modify the segment, based on the command line: */
if (argc == 2) {
printf("writing to segment: \"%s\"\n", argv[1]);
gettimeofday(&t3, NULL);
strncpy(data, argv[1], SHM_SIZE);
gettimeofday(&t4, NULL);
printf("Time to send data to shared memory: %g \n", (t4.tv_sec + t4.tv_usec/1000000.0)-(t3.tv_sec + t3.tv_usec/1000000.0));
} else{
printf("segment contains: \"%s\"\n", data);
}
/* detach from the segment: */
if (shmdt(data) == -1) {
perror("shmdt");
exit(1);
}
return 0;
}
Any idea?
Your shared memory segments are marked as to be destroyed but still have process(es) attached to them.
Per the source code, the nattach column is 2 and the status is "dest", meaning the shared memory segments have 2 attachments and are marked to be destroyed once the last attached process detaches from the segment.
You need to either have the process(es) attached to the segments call shmdt() to detach from the shared memory segments, or you need kill those process(es). Once you do that the segments will be destroyed.
Have you tried (as root):
$ sync; echo 3 > /proc/sys/vm/drop_caches
Not sure this will free your shared memory, but you can try.
If you want to see an example, here goes a gist: https://gist.github.com/hudsantos/7fec7d9c34cc472b7f98
I have a problem to write struct into a mapped memory file.
I have two file namely mmap.write.c and mmap.read.c, and in these files, I'm writing an integer to a file and reading it from file.
When I want to write struct and read it, I could not think about that since in line 32 of mmap.write.c
sprintf((char*) file_memory, "%d\n", i);
and in line 25 of mmap.read.c
sscanf (file_memory, "%d", &integer);
There is no difference to write and read integer/double/float/char etc. since I can put pattern as second argument "%d" for integer. But what I will write here to indicate struct? That is my main problem.
The struct that I want to write and read:
#define CHANNELS 20
typedef dataholder struct {
int value[CHANNELS];
time_t time;
int hash;
}dataholder;
mmap.read.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
int main (int argc, char* const argv[])
{
int fd;
void* file_memory;
int integer;
/* Open the file. */
fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);
printf("file opened\n");
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
printf("memfile opened\n");
close (fd);
printf("file closed\n");
/* Read the integer, print it out, and double it. */
while(1) {
sscanf (file_memory, "%d", &integer);
printf ("value: %d\n", integer);
usleep(100000);
}
//sprintf ((char*) file_memory, "%d\n", 2 * integer);
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
mmap.write.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
/* Return a uniformly random number in the range [low,high]. */
int random_range (unsigned const low, unsigned const high)
{
unsigned const range = high - low + 1;
return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));
}
int main (int argc, char* const argv[])
{
int fd, i;
void* file_memory;
/* Seed the random number generator. */
srand (time (NULL));
/* Prepare a file large enough to hold an unsigned integer. */
fd = open (argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
//lseek (fd, FILE_LENGTH+1, SEEK_SET);
write (fd, "", 1);
//lseek (fd, 0, SEEK_SET);
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);
close (fd);
/* Write a random integer to memory-mapped area. */
for(i=0; i<10000; i++) {
sprintf((char*) file_memory, "%d\n", i);
//goto a;
usleep(100000);
}
a:
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
Thanks a lot in advance.
First of all you have to keep track of where in the memory you want to write, second you have to remember that the mapped memory is just like any other pointer to memory. The last bit is important, as this means you can use normal array indexing to access the memory, or use functions such as memcpy to copy into the memory.
To write a structure, you have three choices:
Write the structure as-is, like in a binary file. This will mean you have to memcpy the structure to a specified position.
Write the structure, field-by-field, as text using e.g. sprintf to the correct position.
Treat the memory as one large string, and do e.g. sprintf of each field into a temporary buffer, then strcat to add it to the memory.
The simplest way is to just use a pointer:
dataholder *dh = file_memory;
/* now you can access dh->value, dh->time, dh->hash */
Since this struct doesn't contain any pointers, if you need to copy it in or out, you can just assign it, like:
dataholder dh_other = *dh;
or
*dh = dh_other;
I'm following http://backreference.org/2010/03/26/tuntap-interface-tutorial/
The following code successfully gets a fd (usually 3) when I run it as root, but it does not create a /dev/tun77 device.
Should it?
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <linux/if_tun.h>
#include <linux/ioctl.h>
#define IFNAMSIZ 16
int tun_alloc(char *dev, int flags) {
struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun";
/* Arguments taken by the function:
*
* char *dev: the name of an interface (or '\0'). MUST have enough
* space to hold the interface name if '\0' is passed
* int flags: interface flags (eg, IFF_TUN etc.)
*/
/* open the clone device */
if( (fd = open(clonedev, O_RDWR)) < 0 ) {
return fd;
}
/* preparation of the struct ifr, of type "struct ifreq" */
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */
if (*dev) {
/* if a device name was specified, put it in the structure; otherwise,
* the kernel will try to allocate the "next" device of the
* specified type */
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
/* try to create the device */
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
close(fd);
return err;
}
/* if the operation was successful, write back the name of the
* interface to the variable "dev", so the caller can know
* it. Note that the caller MUST reserve space in *dev (see calling
* code below) */
strcpy(dev, ifr.ifr_name);
/* this is the special file descriptor that the caller will use to talk
* with the virtual interface */
return fd;
}
int main(void) {
char tun_name[IFNAMSIZ];
int nread, tun_fd;
char buffer[2048];
/* Connect to the device */
strcpy(tun_name, "tun77");
tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI); /* tun interface */
if (tun_fd < 0){
perror("Allocating interface");
exit(1);
} else {
printf("connected to %s on fd: %i\n", tun_name, tun_fd);
}
/* Now read data coming from the kernel */
while (1) {
/* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */
nread = read(tun_fd, buffer, sizeof(buffer));
if (nread < 0) {
perror("Reading from interface");
close(tun_fd);
exit(1);
}
/* Do whatever with the data */
printf("Read %d bytes from device %s\n", nread, tun_name);
}
return EXIT_SUCCESS;
}
Waldner answered this on http://backreference.org/2010/03/26/tuntap-interface-tutorial/ with:
Neither. Network interfaces in Linux don't appear under /dev; the only thing you'll see there is /dev/net/tun, which is the device that should be opened as the first step to create a tun/tap interface.
If you run the sample code, you'll be able to see and configure the interface you create by using "ip link" while the program is running; when the program terminates, the interface disappears.
Alternatively, the interface can be made persistent, as explained, and in that case it will survive program termination.
In any case, no device is created under /dev (apart from the already mentioned /dev/net/tun).
I have a bit of an issue with one of my projects.
I have been trying to find a well documented example of using shared memory with fork() but to no success.
Basically the scenario is that when the user starts the program, I need to store two values in shared memory: current_path which is a char* and a file_name which is also char*.
Depending on the command arguments, a new process is kicked off with fork() and that process needs to read and modify the current_path variable stored in shared memory while the file_name variable is read only.
Is there a good tutorial on shared memory with example code (if possible) that you can direct me to?
There are two approaches: shmget and mmap. I'll talk about mmap, since it's more modern and flexible, but you can take a look at man shmget (or this tutorial) if you'd rather use the old-style tools.
The mmap() function can be used to allocate memory buffers with highly customizable parameters to control access and permissions, and to back them with file-system storage if necessary.
The following function creates an in-memory buffer that a process can share with its children:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
void* create_shared_memory(size_t size) {
// Our memory buffer will be readable and writable:
int protection = PROT_READ | PROT_WRITE;
// The buffer will be shared (meaning other processes can access it), but
// anonymous (meaning third-party processes cannot obtain an address for it),
// so only this process and its children will be able to use it:
int visibility = MAP_SHARED | MAP_ANONYMOUS;
// The remaining parameters to `mmap()` are not important for this use case,
// but the manpage for `mmap` explains their purpose.
return mmap(NULL, size, protection, visibility, -1, 0);
}
The following is an example program that uses the function defined above to allocate a buffer. The parent process will write a message, fork, and then wait for its child to modify the buffer. Both processes can read and write the shared memory.
#include <string.h>
#include <unistd.h>
int main() {
char parent_message[] = "hello"; // parent process will write this message
char child_message[] = "goodbye"; // child process will then write this one
void* shmem = create_shared_memory(128);
memcpy(shmem, parent_message, sizeof(parent_message));
int pid = fork();
if (pid == 0) {
printf("Child read: %s\n", shmem);
memcpy(shmem, child_message, sizeof(child_message));
printf("Child wrote: %s\n", shmem);
} else {
printf("Parent read: %s\n", shmem);
sleep(1);
printf("After 1s, parent read: %s\n", shmem);
}
}
Here is an example for shared memory :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 1024 /* make it a 1K shared memory segment */
int main(int argc, char *argv[])
{
key_t key;
int shmid;
char *data;
int mode;
if (argc > 2) {
fprintf(stderr, "usage: shmdemo [data_to_write]\n");
exit(1);
}
/* make the key: */
if ((key = ftok("hello.txt", 'R')) == -1) /*Here the file must exist */
{
perror("ftok");
exit(1);
}
/* create the segment: */
if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) {
perror("shmget");
exit(1);
}
/* attach to the segment to get a pointer to it: */
if ((data = shmat(shmid, NULL, 0)) == (void *)-1) {
perror("shmat");
exit(1);
}
/* read or modify the segment, based on the command line: */
if (argc == 2) {
printf("writing to segment: \"%s\"\n", argv[1]);
strncpy(data, argv[1], SHM_SIZE);
} else
printf("segment contains: \"%s\"\n", data);
/* detach from the segment: */
if (shmdt(data) == -1) {
perror("shmdt");
exit(1);
}
return 0;
}
Steps :
Use ftok to convert a pathname and a project identifier to a System V IPC key
Use shmget which allocates a shared memory segment
Use shmat to attache the shared memory segment identified by shmid to the address space of the calling process
Do the operations on the memory area
Detach using shmdt
These are includes for using shared memory
#include<sys/ipc.h>
#include<sys/shm.h>
int shmid;
int shmkey = 12222;//u can choose it as your choice
int main()
{
//now your main starting
shmid = shmget(shmkey,1024,IPC_CREAT);
// 1024 = your preferred size for share memory
// IPC_CREAT its a flag to create shared memory
//now attach a memory to this share memory
char *shmpointer = shmat(shmid,NULL);
//do your work with the shared memory
//read -write will be done with the *shmppointer
//after your work is done deattach the pointer
shmdt(&shmpointer, NULL);
try this code sample, I tested it, source: http://www.makelinux.net/alp/035
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main ()
{
int segment_id;
char* shared_memory;
struct shmid_ds shmbuffer;
int segment_size;
const int shared_segment_size = 0x6400;
/* Allocate a shared memory segment. */
segment_id = shmget (IPC_PRIVATE, shared_segment_size,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
/* Attach the shared memory segment. */
shared_memory = (char*) shmat (segment_id, 0, 0);
printf ("shared memory attached at address %p\n", shared_memory);
/* Determine the segment's size. */
shmctl (segment_id, IPC_STAT, &shmbuffer);
segment_size = shmbuffer.shm_segsz;
printf ("segment size: %d\n", segment_size);
/* Write a string to the shared memory segment. */
sprintf (shared_memory, "Hello, world.");
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Reattach the shared memory segment, at a different address. */
shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);
printf ("shared memory reattached at address %p\n", shared_memory);
/* Print out the string from shared memory. */
printf ("%s\n", shared_memory);
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Deallocate the shared memory segment. */
shmctl (segment_id, IPC_RMID, 0);
return 0;
}
Here's a mmap example:
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/*
* pvtmMmapAlloc - creates a memory mapped file area.
* The return value is a page-aligned memory value, or NULL if there is a failure.
* Here's the list of arguments:
* #mmapFileName - the name of the memory mapped file
* #size - the size of the memory mapped file (should be a multiple of the system page for best performance)
* #create - determines whether or not the area should be created.
*/
void* pvtmMmapAlloc (char * mmapFileName, size_t size, char create)
{
void * retv = NULL;
if (create)
{
mode_t origMask = umask(0);
int mmapFd = open(mmapFileName, O_CREAT|O_RDWR, 00666);
umask(origMask);
if (mmapFd < 0)
{
perror("open mmapFd failed");
return NULL;
}
if ((ftruncate(mmapFd, size) == 0))
{
int result = lseek(mmapFd, size - 1, SEEK_SET);
if (result == -1)
{
perror("lseek mmapFd failed");
close(mmapFd);
return NULL;
}
/* Something needs to be written at the end of the file to
* have the file actually have the new size.
* Just writing an empty string at the current file position will do.
* Note:
* - The current position in the file is at the end of the stretched
* file due to the call to lseek().
* - The current position in the file is at the end of the stretched
* file due to the call to lseek().
* - An empty string is actually a single '\0' character, so a zero-byte
* will be written at the last byte of the file.
*/
result = write(mmapFd, "", 1);
if (result != 1)
{
perror("write mmapFd failed");
close(mmapFd);
return NULL;
}
retv = mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0);
if (retv == MAP_FAILED || retv == NULL)
{
perror("mmap");
close(mmapFd);
return NULL;
}
}
}
else
{
int mmapFd = open(mmapFileName, O_RDWR, 00666);
if (mmapFd < 0)
{
return NULL;
}
int result = lseek(mmapFd, 0, SEEK_END);
if (result == -1)
{
perror("lseek mmapFd failed");
close(mmapFd);
return NULL;
}
if (result == 0)
{
perror("The file has 0 bytes");
close(mmapFd);
return NULL;
}
retv = mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0);
if (retv == MAP_FAILED || retv == NULL)
{
perror("mmap");
close(mmapFd);
return NULL;
}
close(mmapFd);
}
return retv;
}