HugeTLB - Large Page Support in the Linux Kernel
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#define MB_1 (1024*1024)
#define MB_8 (8*MB_1)
char *a;
int shmid1;
void init_hugetlb_seg()
{
shmid1 = shmget(2, MB_8, SHM_HUGETLB
| IPC_CREAT | SHM_R
| SHM_W);
if ( shmid1 < 0 ) {
perror("shmget");
exit(1);
}
printf("HugeTLB shmid: 0x%x\n", shmid1);
a = shmat(shmid1, 0, 0);
if (a == (char *)-1) {
perror("Shared memory attach failure");
shmctl(shmid1, IPC_RMID, NULL);
exit(2);
}
}
void wr_to_array()
{
int i;
for( i=0 ; i<MB_8 ; i++) {
a[i] = 'A';
}
}
void rd_from_array()
{
int i, count = 0;
for( i=0 ; i<MB_8 ; i++)
if (a[i] == 'A') count++;
if (count==i)
printf("HugeTLB read success :-)\n");
else
printf("HugeTLB read failed :-(\n");
}
int main(int argc, char *argv[])
{
init_hugetlb_seg();
printf("HugeTLB memory segment initialized !\n");
printf("Press any key to write to memory area\n");
getchar();
wr_to_array();
printf("Press any key to rd from memory area\n");
getchar();
rd_from_array();
shmctl(shmid1, IPC_RMID, NULL);
return 0;
}
Question> I don't have root permission to run this code. What should I do to fix the permission issue?
$ gcc hugetlb-array.c -o hugetlb-array -Wall
$ ./hugetlb-array
shmget: Operation not permitted
Without using SHM_HUGETLB, the code runs well without problem.
$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000002 32768 myid 600 2097152 1
You need the CAP_IPC_LOCK capability. You can add this to an executable using setcap(8).
Specifically, run:
root#yourmachine$ setcap cap_ipc_lock=ep your_executable
This has to be redone every time your executable is modified (recompiled/reinstalled) - otherwise there would be a gaping security hole.
If you only need to do this at startup, you should also consider dropping privileges as soon as possible, but this is not essential (if anyone really cares, you'll probably get a patch).
See also Using setcap in linux
Related
I'm new to pthread and multithreading, i have written a code like that.
#include <pthread.h>
#include <unistd.h>
void *nfc_read(void *arg)
{
int fd = -1;
int ret;
uint8_t read_data[24];
while(1){
ret = read_block(fd, 8, read_data);
if(!ret){
return (void)read_data;
}
}
}
int main(int argc, char *argv[])
{
pthread_t my_thread;
void *returnValue;
pthread_create(&my_thread, NULL, nfc_read, NULL);
pthread_join(my_thread, &returnValue);
printf("NFC card value is : %s \n", (char)returnValue);
printf("other process");
return 0;
}
Until the return value from nfc_read function, as I will have other code I need to run and I don't want to block in main. How can i do that?
This is a sample where a read thread runs concurrently to the "main" thread which is doing other work (in this case, printing dots and sleeping).
To keep things simple, a simulated the reading from an input device with copying a constant string character by character. I guess, this is reasonable as the synchronization of threads is focused.
For the synchronization of threads, I used atomic_bool with atomic_store() and atomic_load() which are provided by the Atomic Library (since C11).
My sample application test-concurrent-read.c:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
/* sampe input */
const char sampleInput[]
= "This is sample input which is consumed as if it was read from"
" a (very slow) external device.";
atomic_bool readDone = ATOMIC_VAR_INIT(0);
void* threadRead(void *pArg)
{
char **pPBuffer = (char**)pArg;
size_t len = 0, size = 0;
int c; const char *pRead;
for (pRead = sampleInput; (c = *pRead++) > 0; sleep(1)) {
if (len + 1 >= size) {
if (!(*pPBuffer = realloc(*pPBuffer, (size + 64) * sizeof(char)))) {
fprintf(stderr, "ERROR! Allocation failed!\n");
break;
}
size += 64;
}
(*pPBuffer)[len++] = c; (*pPBuffer)[len] = '\0';
}
atomic_store(&readDone, 1);
return NULL;
}
int main()
{
/* start thread to read concurrently */
printf("Starting thread...\n");
pthread_t idThreadRead; /* thread ID for read thread */
char *pBuffer = NULL; /* pointer to return buffer from thread */
if (pthread_create(&idThreadRead, NULL, &threadRead, &pBuffer)) {
fprintf(stderr, "ERROR: Failed to start read thread!\n");
return -1;
}
/* start main loop */
printf("Starting main loop...\n");
do {
putchar('.'); fflush(stdout);
sleep(1);
} while (!atomic_load(&readDone));
putchar('\n');
void *ret;
pthread_join(idThreadRead, &ret);
/* after sync */
printf("\nReceived: '%s'\n", pBuffer ? pBuffer : "<NULL>");
free(pBuffer);
/* done */
return 0;
}
Compiled and tested with gcc in cygwin on Windows 10 (64 bit):
$ gcc -std=c11 -pthread -o test-concurrent-read test-concurrent-read.c
$ ./test-concurrent-read
Starting thread...
Starting main loop...
.............................................................................................
Received: 'This is sample input which is consumed as if it was read from a (very slow) external device.'
$
I guess, it is worth to mention why there is no mutex guarding for pBuffer which is used in main() as well as in threadRead().
pBuffer is initialized in main() before pthread_create() is called.
While thread_read() is running, pBuffer is used by it exclusively (via its passed address in pPBuffer).
It is accessed in main() again but not before pthread_join() which grants that threadRead() has ended.
I tried to find a reference by google to confirm that this procedure is well-defined and reasonable. The best, I could find was SO: pthread_create(3) and memory synchronization guarantee in SMP architectures which cites The Open Group Base Specifications Issue 7 - 4.12 Memory Synchronization.
I use execv to run lshw command to get the CPU, disk, and memory in C code. But I would like to search another solution to get these information from /proc or any other existed data. Have any suggestion? Here is my code:
char *params[9] = {"/usr/bin/lshw", "-short", "-c", "disk",
"-c", "memory", "-c", "processor", 0}; //cmd params filled
execv(params[0], params);
Linux command: $ sudo lshw -short -c disk -c processor -c memory
$ sudo lshw -short -c disk -c processor -c memory
H/W path Device Class Description
======================================================
/0/0 memory 64KiB BIOS
/0/22 memory 16GiB System Memory
/0/22/0 memory DIMM Synchronous [empty]
/0/22/1 memory DIMM Synchronous [empty]
/0/22/2 memory 8GiB DIMM Synchronous 2133 MHz (0.5 ns)
/0/22/3 memory 8GiB DIMM Synchronous 2133 MHz (0.5 ns)
/0/2a memory 256KiB L1 cache
/0/2b memory 1MiB L2 cache
/0/2c memory 6MiB L3 cache
/0/2d processor Intel(R) Xeon(R) CPU D-1521 # 2.40GHz
/0/1/0.0.0 /dev/sda disk 16GB SATADOM-SH 3IE3
/0/2/0.0.0 /dev/sdb disk 120GB Patriot Blaze
I have two questions:
Where to find a guide to parse the files in /proc to get
these hardware information?
Do I need to trace the source code of lshw to find what does lshw do?
Edit:
Chapter 7 of Advanced Linux Programming is a guide to parse the /proc filesystem.
The best way to get hardware information is using sysconf() and sysctl*() functions (Mac OS X, freebsd, openbsd), and sysconf() and sysinfo() on Linux.
Parsing /proc/* is slower and more involved than calling sysinfo( ) or sysconf( )
Below is a small example giving you some information about processor and memory on Mac OS X:
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main()
{
char *p = NULL;
size_t len;
sysctlbyname("hw.model", NULL, &len, NULL, 0);
p = malloc(len);
sysctlbyname("hw.model", p, &len, NULL, 0);
printf("%s\n", p);
/* CTL_MACHDEP variables are architecture dependent so doesn't work
for every one */
sysctlbyname("machdep.cpu.brand_string", NULL, &len, NULL, 0);
p = malloc(len);
sysctlbyname("machdep.cpu.brand_string", p, &len, NULL, 0);
printf("%s\n", p);
int64_t mem;
len = sizeof(mem);
sysctlbyname("hw.memsize", &mem, &len, NULL, 0);
printf("System Memory : %lld\n", mem);
return (0);
}
You have to read man 3 sysctl, or on Linux man 2 sysconf and man 2 sysinfo.
An interesting link : http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system#Other
You can calculate the CPU load and usage retrieving some sysctl variables, and doing the math by yourself (you can find the formulas to do it on google).
But where to find the physical DIMM information as the report from $ sudo lshw -short -c memory ?
You can execute your command inside your C program to save it as a string like :
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
char *strjoin(char *s1, char *s2, int n)
{
int i = strlen(s2);
int j = 0;
if ((s2 = realloc(s2, (i + n + 1))) == NULL)
perror(0);
while (j < n && s1[j])
{
s2[i] = s1[j];
i++;
j++;
}
s2[i] = 0;
return (s2);
}
int main()
{
pid_t father;
char buf[500] = {0};
char *str;
char *argv[5] = {"/usr/bin/lshw", "-short", "-c", "memory"};
int fd[2];
int ret;
if (pipe(fd) == -1)
{
perror(NULL);
return -1;
}
father = fork();
if (father == 0)
{
close(fd[1]);
while ((ret = read(fd[0], buf, 500)))
{
str = strjoin(buf, str, ret);
}
close(fd[0]);
}
else
{
close(fd[0]);
execv(argv[0], argv);
close(fd[1]);
wait(0);
}
wait(0);
printf("%s", str);
return 0;
}
(I don't check all the function's return in this code, not to have a too long one, but you should do it in your program).
Here is an example of parsing the file /proc/meminfo to save in a double array 2 strings I want, and then printing them out :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *f;
char *line = NULL;
ssize_t read;
size_t len = 0;
char **info;
int i = 0;
info = malloc(3 * sizeof(char*));
f = fopen("/proc/meminfo", "r");
while ((read = getline(&line, &len, f)) != -1)
{
if (strstr(line, "MemTotal") != NULL)
info[i] = strdup(line);
else if (strstr(line, "MemFree") != NULL)
info[i] = strdup(line);
i++;
}
info[i] = 0;
fclose(f);
i = 0;
while (info[i])
{
printf("%s", info[i]);
free (info[i]);
i++;
}
free (info);
return 0;
}
If you want to save more strings, malloc more space in the double array info, and add them with else if inside the read loop. You can do that with any files from /proc/ to get the information you need.
By reading the source code of lshw, I found that lshw read raw data from /sys/class/dmi/. Because lshw is written in CPP that I am not familiar with, there is a question Where does dmidecode get the SMBIOS table? mentioned that dmidecode.c read raw data from /sys/class/dmi that's same as lshw does.
Here are the definitions in dmidecode.c
#define SYS_ENTRY_FILE "/sys/firmware/dmi/tables/smbios_entry_point"
#define SYS_TABLE_FILE "/sys/firmware/dmi/tables/DMI"
I extract code from dmidecode.c to get the CPU and memory information, and use lsscsi to get disk information.
Thanks for your help.
1: To get the CPU load use this command :
top -bn1 | grep load
this will give you output like :
top - 12:26:20 up 35 min, 2 users, load average: 0.02, 0.01, 0.00
now parse the load average from above string.
2: To get memory info use this command :
free -m
This will give you:
total used free shared buffers cached
Mem: 15926 308 15617 6 15 122
-/+ buffers/cache: 171 15755
Swap: 0 0 0
To get the disk info , use this :
df -H /home/test
This will give you :
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 102G 5.4G 91G 6% /
Now from above result parse the content what you want.
I'm trying to communicate two programs (in one I used GTK and in the other I used the Standard IO of C programing). In both I used shmget. shmat, ..., etc, to communicate them both.
However I'm having to much trouble to get the things done... Both programs do compile but none of them runs according my intentions.
What I'm really want to do is send data from the server to a client controlling the client program (in this test just printing the numbers on terminal), which will finish its execution after receives a signal from the server.
Unfortunately I couldn't made it with GTK but I almost did it in console application, however whem it is running automatic (without user interactivity) the Client crashes after 65516 iterations. In gaming programs this could be a problem, however for some applications the codes below will work satisfactorily.
My question is: Why an error occurs after reached 65516 interations (calls of shmat function on client program)?
In my future application this error have to be avoided or it will make the program crash...
How can I avoid it and keep my program (the client application) running indefinitely?
There are other ways to control a program through another program? which one is feasible or more practical?
File
smh-02.h
#define NOT_READY -1
#define FILLED 0
#define TAKEN 1
struct Memory
{
int status;
int data[4];
int dado; // I just add this data
};
File Console_server01.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "shm-02.h"
#define RUN_WITH_USER // Coment this line to user interactivity
// Or uncoment it to run automactic test indefinitely until segmented fail
key_t ShmKEY;
int ShmID;
struct Memory *ShmPTR;
//---------------------------------------------------------------------
void send_data(int info)
{
while(ShmPTR->status != TAKEN);
ShmPTR->status = NOT_READY;
ShmPTR->dado = info;
ShmPTR->status = FILLED; //Server has informed client that the shared memory have been FILLED
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
int main(int argc, char *argv[])
{
int info;
ShmKEY = ftok(".", 'x');
ShmID = shmget(ShmKEY, sizeof(struct Memory), IPC_CREAT | 0666);
if (ShmID < 0)
{
printf("*** shmget error (server) ***\n");
exit(1);
}
ShmPTR = (struct Memory *) shmat(ShmID, NULL, 0);
if ((int) ShmPTR == -1)
{
printf("*** shmat error (server) ***\n");
exit(1);
}
send_data(55); // This will send some signal to the client establish connection
info = 1; //----- Value to RUN_REPEATLY ------
do
{
#ifdef RUN_WITH_USER //----------------------------------
printf("\n Type:");
printf("\n [1] To move to RIGHT");
printf("\n [2] To move to LEFT");
printf("\n [3] To move to QUIT");
printf("\n You choice is: ");
scanf("%d",&info);
#endif //----------------------------------
send_data(info);
}
while(info != 3);
shmdt((void *) ShmPTR); //Server has detached its shared memory...
shmctl(ShmID, IPC_RMID, NULL); //Server has removed its shared memory...
return 0;
}
File Console_client01.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "shm-02.h"
int main(void)
{
key_t ShmKEY;
int ShmID;
struct Memory *ShmPTR;
ShmKEY = ftok(".", 'x');
int i = 0;
int trigger = 0; // trigger locked
ShmID = shmget(ShmKEY, sizeof(struct Memory), 0666);
if (ShmID < 0)
{
printf("*** shmget error (client) ***\n");
exit (1); //Client exits
}
do{
ShmPTR = (struct Memory *) shmat(ShmID, NULL, 0);
if ( (ShmPTR->status == FILLED)&&(trigger == 0) )
{
ShmPTR->status = TAKEN;
trigger = 1; // trigger pulled
}
while (ShmPTR->status != FILLED)
{
printf("\nWaiting status = FILLED\t|\t");
switch(ShmPTR->status)
{
case -1:
printf("Current status = NOT_READY");
break;
case 0:
printf("Current status = FILLED");
break;
case 1:
printf("Current status = TAKEN");
break;
}
sleep(1); // Uncoment this line to better user interactivity
}
usleep(800); // Uncoment this line to better user interactivity
i++;
printf("\ni = %d --/// | dado = %d ", i, ShmPTR->dado);
if ((int) ShmPTR == -1)
{
printf("*** shmat error (client) ***\n");
exit(1); //Client exits
}
else
{
if (ShmPTR->dado == 55)
{
printf("\nConnection ESTABLISHED"); //Go to the LEFT
ShmPTR->status = TAKEN;
}
if (ShmPTR->dado == 3) // Exiting Program
{
ShmPTR->status = TAKEN; //Client has informed server data have been taken...
shmdt((void *) ShmPTR); //Client has detached its shared memory...
exit (0); //Client exits
}
if (ShmPTR->dado == 1)
{
printf("\n<--- move LEFT"); //Go to the LEFT
ShmPTR->status = TAKEN;
}
if (ShmPTR->dado == 2)
{
printf("\n---> move RIGHT"); // Go to the RIGHT
ShmPTR->status = TAKEN;
}
if ( (ShmPTR->dado != 1)||(ShmPTR->dado != 2) )
{
printf("\nIdle | dado = %d",ShmPTR->dado ); //Doing NOTHING
ShmPTR->status = TAKEN;
}
}
}while (1); // 'Infinite' loop
exit(0);
}
Running the programs_Picture
Error after 65516 interations_Picture
You should never use shared memory for communication. It is not type safe and hard to code correctly.
What you truly need is serialization. Consider using JSON-RPC for communication. Yes, it is far slower than raw memory manipulation, but much safer, more portable and easier to make just work. Some even use it for heavy and often loads, let alone occasional loads like GUI input.
I usually code C in linux. I am using now a Mac and I am new on this machine.
In linux when I use shared memory between process, the memory is allocated as a file which pathname is /dev/shm/resource_name.
I was trying a simple code and suddenly I got an error.
It wasn't able to call a function destroy() to destroy the shared memory.
Usually when this happens I delete the file manually on the directory.
My question is: Where is located the shared memory in OS X. Because when I try recompile and execute, the gcc compiler tells me that the resource already exists and I don't know how to delete it.
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
int increment (int n)
{
n = n + 1;
printf ("%d\n", n);
return n;
}
int *create ()
{
int *ptr;
int ret;
int fd= shm_open ("/shm", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror ("shm");
exit (1);
}
ret = ftruncate (fd, sizeof (int));
if (ret == -1) {
perror ("shm");
exit (2);
}
ptr = mmap (0, sizeof (int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
perror ("shm-mmap");
exit (3);
}
return ptr;
}
void destroy (int *ptr)
{
int ret;
ret = munmap (ptr, sizeof (int));
if (ret == -1) {
perror ("shm");
exit (7);
}
ret = shm_unlink ("shm");
if (ret == -1) {
perror ("shm");
exit (8);
}
}
int main (int argc, char *argv[])
{
sem_t *semaphore;
int *ptr = create ();
int numProcessesChilds, numIncrements;
int i;
if (argc == 3) {
numProcessesChilds = atoi (argv [1]);
numIncrements = atoi (argv [2]);
}
else {
numProcessesChilds = 10;
numIncrements = 1;
}
*ptr = 0;
semaphore = sem_open("/semaphore", O_CREAT, 0xFFFFFFFF, 1);
if (semaphore == SEM_FAILED) {
perror("semaphore");
}
for (i = 0; i < numProcessesChilds; i++) {
switch (fork ()) {
case -1:
perror ("fork");
exit (1);
case 0:
sem_wait(semaphore);
for (i = 0 ; i < numIncrements; i++) {
(*ptr) = increment (*ptr);
}
sem_post(semaphore);
exit (0);
}
}
for (i = 0; i < numProcessesChilds; i++) {
wait (NULL);
}
sem_close(semaphore);
sem_unlink("/semaphore");
printf ("Fina value: %d\n", *ptr);
destroy (ptr);
return 0;
}
Answered here, Mac OS being derived from BSD does not expose any entry in the file system for shared memory objects. The corresponding files in /dev/shm are Linux specific.
Under Mac OS, only shm_unlink() will do the cleanup job. The OP's example program should work upon each startup as it passes O_CREAT flag to shm_open(). If the shared memory object does not already exist, it is created otherwise it is opened as it is. As the resulting memory area pointed by ptr is reset with the instruction *ptr = 0 at the beginning of the program, everything should work properly.
Mac OS X , like linux is UNIX based so it handles the shared memory just like Linux. The shared memory segments you allocate are also files located in /dev/shm
To destroy the shared memory you can use the command ipcs -m or ipcs -M to view all the shared memory, look for yours and then execute ipcrm -m shmid where shmid would be the id of your shared memory. You can also do ipcrm -M shmkey using the key you assigned to it
I'm fairly unexperienced with C and am running into a "Bus error" that I cannot understand the cause of. I had never heard of gdb but came across it on this forum and tried using it on my problem program and got the following output:
% gdb Proc1 GNU gdb 5.0
...
This GDB was
configured as
"sparc-sun-solaris2.8"...
(no
debugging symbols found)...
(gdb) run
Starting program:
/home/0/vlcek/CSE660/Lab3/Proc1
(no
debugging symbols found)...
(no
debugging symbols found)...
(no
debugging symbols found)...
Program
received signal SIGSEGV, Segmentation
fault. 0x10a64 in main ()
I have no idea what this means, is that saying there's an error in line 10 in my code? If so, line 10 in my code is merely "int main()" so I'm not sure the issue there... When I try running the program all it says is "Bus error" so I'm not sure where to go from here. I even tried putting a printf right after main and it doesn't print the string, only gives me a Bus error.
Below is my code:
// Compilation Command: gcc -o Proc1 Proc1.c ssem.o sshm.o
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ssem.h"
#include "sshm.h"
// Code of Proc1
int main()
{int i, internal_reg;
int key1 = 111111, key2 = 222222, key3 = 333333, key4 = 444444;
/* here create and initialize all semaphores */
int sem1 = sem_create(key1, 1);
if (sem1 < 0) {
perror("sem failed");
}
int sem2 = sem_create(key2, 1);
if (sem2 < 0) {
perror("sem failed");
}
int sem3 = sem_create(key3, 1);
if (sem3 < 0) {
perror("sem failed");
}
int sem4 = sem_create(key4, 1);
if (sem4 < 0) {
perror("sem failed");
}
/* here created: shared memory array Account of size 3 */
int *Account;
int shmid = shm_get(123456, (void**) &Account, 3*sizeof(int));
if (shmid < 0) {
perror("shm failed");
}
Account[0]=10000;
Account[1]=10000;
Account[2]=10000;
/* synchronize with Proc2, Proc3 and Proc4 (4 process 4 way synchronization)*/
for (i = 0; i < 1000; i++)
{
sem_signal(sem1);
sem_signal(sem1);
sem_signal(sem1);
internal_reg = Account[0];
internal_reg = internal_reg - 200;
Account[0] = internal_reg;
/* same thing, except we're adding $100 to Account1 now... */
internal_reg = Account[1];
internal_reg = internal_reg + 200;
Account[1] = internal_reg;
if (i % 100 == 0 && i != 0) {
printf("Account 0: $%i\n", Account[0]);
printf("Account 1: $%i\n", Account[1]);
}
if (i == 300 || i == 600) {
sleep(1);
}
sem_wait(sem2);
sem_wait(sem3);
sem_wait(sem4);
}
/* Here add a code that prints contents of each account
and their sum after 100th, 200th, 300th, ...., and 1000th iterations*/
}
/*in the code above include some wait and signal operations on semaphores. Do no
t over-synchronize. */
Here is the documentation for ssem and sshm:
/*
* ssem.c
*
* Version 1.0.0
* Date : 10 Jan 2002
*
*/
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "ssem.h"
#define PERMS 0600
static struct sembuf op_lock[1] = {
0, -1, 0
};
static struct sembuf op_unlock[1] = {
0, 1, IPC_NOWAIT
};
int sem_create(int key,int initval)
{
int semid,i;
semid = semget((key_t)key, 1, IPC_CREAT | PERMS);
for(i=0;i<initval;i++)
semop(semid,&op_unlock[0],1);
return semid;
}
int sem_open(int key)
{
int semid;
semid = semget(key,0,0);
return semid;
}
int sem_wait(int semid)
{
return semop(semid,&op_lock[0],1);
}
int sem_signal(int semid)
{
return semop(semid,&op_unlock[0],1);
}
int sem_rm(int semid)
{
return semctl(semid, 0, IPC_RMID, 0);
}
/*
* sshm.c
*
* Routines for Simpler shared memory operations
* Version : 1.0.0.
* Date : 10 Jan 2002
*
*/
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include "sshm.h"
#define PERMS 0600
int shm_get(int key, void **start_ptr, int size)
{
int shmid;
shmid = shmget((key_t) key, size, PERMS | IPC_CREAT);
(*start_ptr) = (void *) shmat(shmid, (char *) 0, 0);
return shmid;
}
int shm_rm(int shmid)
{
return shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0);
}
After compiling Proc1.c with the -ggdb flag and running gdb I got the following:
Program received signal SIGSEGV,
Segmentation fault. 0x10a64 in main ()
at Proc1.c:36
36 Account[0]=10000
Why would this cause a segmentation fault?
After changing the declaration of Account to
int *Account = 0;
and adding
printf("Account == %p\n", Account);
before Account[0] = 10000;
I get the following upon running Proc1:
Account == ffffffff
Bus error
In order to get more sensible results from gdb you should compile your program with the -ggdb option. This will then include debugging information (like line numbers) into your program.
What you are currently seeing is the memory address (0x10a64) of the program counter. This will not help you very much unless you can correlate the assembly instructions you find there with a part of your C program yourself.
It looks like you are using shm_get properly. I think the library designer has made a terrible mistake in naming the function so similarly to shmget.
It's just as I thought. The Account pointer is ending up with an invalid value (aka 0xffffffff (aka (void *)(-1))) in it. The value (void *)(-1) generally indicates some sort of error, and it is explicitly mentioned in the manpage for shmat. This indicates that the shmat call inside the library failed. Here is how you can tell if it failed:
if (Account == (void *)(-1)) {
perror("shmat failed");
}
Account[0] = 10000;
// ...
Now, why it failed is an interesting mystery. Apparently the shmget call succeeded.
Personally, I think System V IPC is basically deprecated at this point and you should avoid using it if you can.
Depending on your compiler and your compiler options you might encounter an aliasing problem because your are casting the address of your Account pointer. These oldish interfaces are not in phase with modern antialiasing rules, meaning that the optimizer supposes that the value of Account wouldn't change.
Also you should get the argument for shm_get as close as possible to the expected type. Try perhaps something like the following.
void volatile* shmRet;
int shmid = shm_get(123456, (void**) &shmRet, 3*sizeof(int));
int *Account = shmRet;
I don't have the same architecture, so I don't know the exact prototype of your shm_get but usually it is also a bad idea to use fixed keys for this type of functions. There should be some function that returns you some key to use in your application.