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.
Related
Like title says, when I start ubuntu terminal first time after I start my computer it works fine but after I compile my program I'm getting segmentation fault error. Not sure if it's worth to mention but I use ubuntu on windows 10.
My semaphore.c:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h> /* for O_* constants */
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h> /* random */
#include <unistd.h> /* sleep */
#define SHMSIZE 128
#define SHM_R 0400
#define SHM_W 0200
float getRandom(float min, float max) {
// this function returns a random number between min - max
float scale = rand() / (float) RAND_MAX;
return min + scale * (max - min);
}
int main(int argc, char **argv)
{
const char *semName1 = "my_sema1";
const char *semName2 = "my_sema2";
struct shm_struct {
int buffer[10];
// unsigned empty;
int next_in, next_out;
};
volatile struct shm_struct *shmp = NULL;
char *addr = NULL;
pid_t pid = -1;
int var1 = 0, var2 = 0, shmid = -1;
struct shmid_ds *shm_buf;
/* init semaphores */
sem_t *sem_id1 = sem_open(semName1, O_CREAT, O_RDWR, 10);
sem_t *sem_id2 = sem_open(semName2, O_CREAT, O_RDWR, 0);
int i, status;
/* allocate a chunk of shared memory */
shmid = shmget(IPC_PRIVATE, SHMSIZE, IPC_CREAT | SHM_R | SHM_W);
shmp = (struct shm_struct *) shmat(shmid, addr, 0);
// shmp->empty = 0;
pid = fork();
/* index in buffer */
shmp->next_in = 0;
shmp->next_out = 0;
if (pid != 0) {
/* here's the parent, acting as producer */
while (var1 < 100) {
float random_time = getRandom(0.1, 2.0); /* random between [0.1s - 2.0s] */
usleep(random_time * 1000000); // sleep
sem_wait(sem_id1); // locks the sem, decreases its value
var1++;
printf("Sending %d\n", var1); fflush(stdout);
shmp->buffer[shmp->next_in] = var1;
shmp->next_in = shmp->next_in + 1 % 10;
sem_post(sem_id2);
}
sem_close(sem_id1);
sem_close(sem_id2);
wait(&status);
sem_unlink(semName1);
sem_unlink(semName2);
shmdt(addr);
shmctl(shmid, IPC_RMID, shm_buf);
} else {
/* here's the child, acting as consumer */
while (var2 < 100) {
float random_time2 = getRandom(0.1, 2.0); /* random between [0.1s - 2.0s] */
usleep(random_time2 * 1000000); // sleep
sem_wait(sem_id2);
var2 = shmp->buffer[shmp->next_out];
printf("Received %d\n", var2); fflush(stdout);
shmp->buffer[shmp->next_out] = -1; // remove
shmp->next_out = shmp->next_out + 1 % 10;
sem_post(sem_id1);
}
sem_close(sem_id1);
sem_close(sem_id2);
shmdt(addr);
shmctl(shmid, IPC_RMID, shm_buf);
}
}
Other than that, I'm trying to implement a bounded buffer with two semaphores where the producer puts items in buffer and customer reads them, does this code make sense? I don't see why I'm getting segmentation error.
Taking a stab a this with my little magic-8 ball:
sem_t *sem_id1 = sem_open(semName1, O_CREAT, O_RDWR, 10);
So the semaphore is initialized to 10.
pid = fork();
/* index in buffer */
shmp->next_in = 0;
shmp->next_out = 0;
next_in and next_out get set to 0 by both parent and child. This can happen at different times after the fork() for parent and child. RACE CONDITION waiting to happen.
sem_wait(sem_id1); // locks the sem, decreases its value
We know sem_id1 is 10 so this never blocks for the first 10 loops.
shmp->buffer[shmp->next_in] = var1;
shmp->next_in = shmp->next_in + 1 % 10;
Three accesses to next_in that are not guarded from the initialization by the child. So you might enqueue 10 numbers or anywhere in those first 10 loops the next_in gets reset to 0 and you overwrite stuff.
if (pid != 0) {
} else {
}
What if pid is -1 because fork() failed? The parent would wait forever on sem_id2.
Your shared buffer isn't volatile. If the compiler can reason out that the buffer can't be aliased by sem_id1 and sem_id2 and maybe a few others it could just fill the buffer with {90, 91, 92, 93, 94, 95, 96, 97, 98, 99} at the end of the loop.
On a even lower level you have no memory barriers. Just because one CPU core was told to write var1 to memory in no way means that this becomes observable by other cores. First the value lands in the CPUs write buffer, then the L1 cache, then L2, then L3 and finally in main memory. If it gets flushed out at all. It could never leave the write buffer or stay in L1 cache for the duration of the program. It probably works on x86 but probably fails on everything else.
Lots of undefined behavior there but nothing I would expect to segfault. Ask your debugger to tell you where it faults.
But then I see this in both the parent and the child:
shmdt(addr);
shmctl(shmid, IPC_RMID, shm_buf);
From the manpage:
The caller must be the owner or creator of the segment, or be privileged.
The parent is the only owner of the shared memory segment and it will be destroyed. But the child is potentially still running and tries to access the buffer. Overall you return and free it twice.
I believe you have to move the call to
shmp = (struct shm_struct *) shmat(shmid, addr, 0);
after the fork so the shm_nattch gets incremented by both the parent and child and later decremented by each. That would be my guess for the segfault.
Update: sem_post() probably includes a full memory barrier so that might actually flush everything to main memory.
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
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 am learning semaphores in C using Ubuntu right now. The professor just throw us this code and ask us to study it and observe. When I compiled I get a warning that ctime(&sem_buf.sem_ctime) returns an int, not a char * but nothing major. When I run it the output is just: Semaphore identifier: 0 Segmentation fault (core dumped). I am very confused as of what went wrong and I have no idea what is going on in this code. Some help would be very much appreciated.
Here is the code:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
# define NS 3
union semun {
int val;
struct semid_ds *buf;
ushort *array; // Unsigned short integer.
};
int main(void)
{
int sem_id, sem_value, i;
key_t ipc_key;
struct semid_ds sem_buf;
static ushort sem_array[NS] = {3, 1, 4};
union semun arg;
ipc_key = ftok(".", 'S'); // Creating the key.
/* Create semaphore */
if ((sem_id = semget(ipc_key, NS, IPC_CREAT | 0666)) == -1) {
perror ("semget: IPC | 0666");
exit(1);
}
printf ("Semaphore identifier %d\n", sem_id);
/* Set arg (the union) to the address of the storage location for */
/* returned semid_ds value */
arg.buf = &sem_buf;
if (semctl(sem_id, 0, IPC_STAT, arg) == -1) {
perror ("semctl: IPC_STAT");
exit(2);
}
printf ("Create %s", ctime(&sem_buf.sem_ctime));
/* Set arg (the union) to the address of the initializing vector */
arg.array = sem_array;
if (semctl(sem_id, 0, SETALL, arg) == -1) {
perror("semctl: SETALL");
exit(3);
}
for (i=0; i<NS; ++i) {
if ((sem_value = semctl(sem_id, i, GETVAL, 0)) == -1) {
perror("semctl : GETVAL");
exit(4);
}
printf ("Semaphore %d has value of %d\n",i, sem_value);
}
/*remove semaphore */
if (semctl(sem_id, 0, IPC_RMID, 0) == -1) {
perror ("semctl: IPC_RMID");
exit(5);
}
}
You need to include time.h to the compiler recognize ctime function. The warning is because the compiler don't know ctime is a function and that returns an char*. By default GCC assumes the unknown function returns an int.
I want to get other process' argv like ps.
I'm using Mac OS X 10.4.11 running on Intel or PowerPC.
First, I read code of ps and man kvm, then I wrote some C code.
#include <kvm.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include <paths.h>
int
main(void) {
char errbuf[1024];
kvm_t *kd = kvm_openfiles(_PATH_DEVNULL, NULL, _PATH_DEVNULL, O_RDONLY, errbuf);
int num_procs;
if (!kd) { fprintf(stderr, "kvm_openfiles failed : %s\n", errbuf); return 0; }
struct kinfo_proc *proc_table = kvm_getprocs(kd, KERN_PROC_ALL, 0, &num_procs);
for (int i = 0; i < num_procs; i++) {
struct kinfo_proc *pproc = &proc_table[i];
char **proc_argv = kvm_getargv(kd, pproc, 0);
printf("%p\n", proc_argv);
}
kvm_close(kd);
return 0;
}
When ran on PowerPC, kvm_getargv() always returned NULL. When ran
on Intel, kvm_openfiles() failed with error /dev/mem: No such file
or directory.
Of cource, I know about permission.
Second, I tried sysctl.
#include <sys/sysctl.h>
#include <stdio.h>
#include <stdlib.h>
#define pid_of(pproc) pproc->kp_proc.p_pid
int
main(void) {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
int buffer_size;
sysctl(mib, 4, NULL, &buffer_size, NULL, 0);
struct kinfo_proc *result = malloc(buffer_size);
sysctl(mib, 4, result, &buffer_size, NULL, 0);
int num_procs = buffer_size / sizeof(struct kinfo_proc);
for (int i = 0; i < num_procs; i++) {
struct kinfo_proc *pproc = result + i;
int mib[3] = { CTL_KERN, KERN_PROCARGS, pid_of(pproc) }; // KERN_PROC_ARGS is not defined
char *proc_argv;
int argv_len;
sysctl(mib, 3, NULL, &argv_len, NULL, 0);
proc_argv = malloc(sizeof(char) * argv_len);
sysctl(mib, 3, proc_argv, &argv_len, NULL, 0);
fwrite(proc_argv, sizeof(char), argv_len, stdout);
printf("\n");
free(proc_argv);
}
return 0;
}
By fwrite, I got argv[0] but argv[1..] are not (environment variables
are printed out.)
There is no more way to do it?
In 10.6, KERN_PROCARGS2 is available: https://gist.github.com/770696
This way is used from ps, procfs on MacFUSE, etc.
I've actually been needing the same thing for a Python library I'm writing, and in my searching I came across another Python lib (PSI) that implements this in C code. It's part of the python module code for listing processes and includes listing the arguments for each process as well. You could take a look at the source code for that for a working example:
darwin_process.c - scroll down to set_exe() for the relevant code
Note: the site is really slow so you'll have to be a bit patient while it loads.