I am trying to test the action of semaphores by calling them in my program with manual switches. I have the functions ready to go, but am failing to codinate them during the calling. I using UNIX system.
Please NOTE: the function defitions are fine, put them here for quick refence.The problem is with the caline below these function. I will be greatful for any assistance.
//----------------semmaphore.h ---------------------------------
#define SEM_NAME "semaphore.h",'a'
#define SEM_MAX 3
#define FREE 0
#define DATA 1
#define ROOM 2
#define S_WAIT -1
#define S_SIGNAL 1
#define NO_EVENT -1
int sem_config(int, int);
int sem_wait(int, int);
int sem_signal(int, int);
//----------------semmaphore.c ---------------------------------
#include <assert.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include "semaphore.h"
static int sem_id;
static union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
ushort array[1];
} sem_attr;
static struct sembuf asem[1];
static key_t s_key;
int sem_config(int event, int init_val)
{
int x;
s_key = ftok(SEM_NAME);
if ( -1 == (sem_id = semget(s_key, SEM_MAX, 0666|IPC_CREAT ) ) {
perror("semget");
return -1;
}
if ( event == NO_EVENT )
return 0;
sem_attr.val = init_val;
if ( -1 == semctl(sem_id, event, SETVAL, sem_attr ) )
{
perror("semctl SETVAL");
return -1;
}
if ( -1 == ( x = semctl(sem_id, event, GETVAL, sem_attr ) ) )
{
perror("semctl GETVAL");
return -1;
}
assert( x == init_val );
return 0;
}
//------------------------------------------------------------
int sem_wait(int event, int nwaits)
{
asem[0].sem_num = event;
asem[0].sem_op = nwaits * S_WAIT;
asem[0].sem_flg = 0;
if ( event == NO_EVENT ) /*remove semaphore set*/
if ( -1 == semctl(sem_id, 0, IPC_RMID, sem_attr ) )
{
perror("semctl IPC_RMID");
return -1;
}
else
return 0;
if ( -1 == semop(sem_id, asem, 1 ) )
{
perror("semop");
return -1;
}
return 0;
}
//------------------------------------------------------------
int sem_signal(int event, int nsignals)
{
asem[0].sem_num = event;
asem[0].sem_op = nsignals * S_SIGNAL;
asem[0].sem_flg = 0;
if ( event == NO_EVENT )
if ( -1 == semctl(sem_id, 0, IPC_RMID, sem_attr ) )
{
perror("semctl IPC_RMID");
return -1;
}
else
return 0;
if ( -1 == semop(sem_id, asem, 1 ) )
{
perror("semop");
return -1;
}
return 0;
}
//========================PROBLEM STARTS HERE=================
#include <stdio.h>
#include "semaphore.h"
main()
{
char op, discard;
int event, nval;
do {
printf("Enter semaphore operation ");
printf("s(ignal)/w(ait)/i(nit)/f(ind)/c(leanup)");
scanf("%c%c", &op, &discard);
printf("Enter semaphore no and initial value :");
scanf("%d%d%c",&event,&nval,&discard);
switch ( op )
{
case 'i':
// Get semaphore for the forks
sem_config(event, nval);
printf("Initialized semaphore\n");
break;
case 'f':
break;
case 's':
sem_signal(event, 1)
break;
case 'w':
sem_wait(event, nval)
break;
case 'c':
break;
default:
if ( -1 == sem_wait(NO_EVENT, 0) )
{
printf("semctl IPC_RMID failed\n");
exit(1);
}
printf("done\n");
exit(0);
}
} while (1);
return 0;
}
Semaphores are for interprocess communication. So you need at least two processes. Testing them with only a single process is pointless :-)
Start your program twice and then type the appropriate commands (wait in #1, signal in #2, etc).
Related
In this code, I am trying to monitor two paths at the same time. I used while(1) for this purpose. But the problem that I am facing is that whenever I run the code, it gives me the same result two times like this.
Giving result
Pathname1 "file" is modified
Pathname1 "file" is modified
Expected result
Pathname1 "file" is modified
I debugged the code. After breaking the main function and stepping over it, the next command stops at this line length = read(fd, buffer, EVENT_BUF_LEN ). Whenever I break a line after this length variable command, the program starts and after modifying the file, the program stops at this line struct inotify_event *event = ( struct inotify_event *)&buffer[i]; Although the program should not break.
I also used IN_CLOSE_WRITE instead of IN_MODIFY but no change in the result.
typedef struct{
int length, fd, wd1, wd2;
char buffer[4096] __attribute__ ((aligned(__alignof__(struct inotify_event))));
} notification;
notification inotify;
int getNotified(char *pathname1, char *pathname2){
inotify.fd = inotify_init();
inotify.wd1 = inotify_add_watch(inotify.fd, pathname1, IN_MODIFY);
inotify.wd2 = inotify_add_watch(inotify.fd, pathname2, IN_MODIFY);
while(1){
inotify.length = read(inotify.fd, inotify.buffer, EVENT_BUF_LEN);
int i = 0;
while(i < inotify.length){
struct inotify_event *event = (struct inotify_event *)&inotify.buffer[i];
if(event->len){
if(event->mask & IN_MODIFY){
if(event->wd == inotify.wd1){
printf("Pathname1 '%s' is modified\n", event->name);
break;
}
if(event->wd == inotify.wd2){
printf("Pathname2 '%s' is modified\n", event->name);
break;
}
}
}
i += EVENT_SIZE + event->len;
}
}
inotify_rm_watch(inotify.fd, inotify.wd1);
inotify_rm_watch(inotify.fd, inotify.wd2);
close(inotify.fd);
exit(0);
}
Some remarks:
You should not "break" as you go out of the inside "while" loop and call read() again
The IN_MODIFY event does not fill the event->name field (i.e. event->len = 0)
The number of IN_MODIFY events depends on how you modify the files ("echo xxx >> file" = write only = 1 IN_MODIFY; "echo xxx > file" = truncate + write = 2 IN_MODIFY)
Here is a proposition for your program (with additional prints):
#include <stdio.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <stdlib.h>
#define EVENT_BUF_LEN 4096
#define EVENT_SIZE sizeof(struct inotify_event)
typedef struct{
int length, fd, wd1, wd2;
char buffer[EVENT_BUF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));
} notification;
notification inotify;
int getNotified(char *pathname1, char *pathname2){
inotify.fd = inotify_init();
inotify.wd1 = inotify_add_watch(inotify.fd, pathname1, IN_MODIFY);
printf("wd1 = %d\n", inotify.wd1);
inotify.wd2 = inotify_add_watch(inotify.fd, pathname2, IN_MODIFY);
printf("wd2 = %d\n", inotify.wd2);
while(1){
inotify.length = read(inotify.fd, inotify.buffer, EVENT_BUF_LEN);
int i = 0;
printf("read() = %d\n", inotify.length);
while(i < inotify.length){
struct inotify_event *event = (struct inotify_event *)&inotify.buffer[i];
printf("event->len = %u\n", event->len);
if(event->mask & IN_MODIFY){
if(event->wd == inotify.wd1){
printf("Pathname1 is modified\n");
} else if (event->wd == inotify.wd2){
printf("Pathname2 is modified\n");
}
}
i += (EVENT_SIZE + event->len);
printf("i=%d\n", i);
}
}
inotify_rm_watch(inotify.fd, inotify.wd1);
inotify_rm_watch(inotify.fd, inotify.wd2);
close(inotify.fd);
exit(0);
}
int main(void)
{
getNotified("/tmp/foo", "/tmp/bar");
return 0;
} // main
Here is an example of execution:
$ gcc notif.c -o notif
$ > /tmp/foo
$ > /tmp/bar
$ ./notif
wd1 = 1
wd2 = 2
====== Upon "> /tmp/foo": 1 event (truncate operation)
read() = 16
event->len = 0
Pathname1 is modified
i=16
====== Upon "echo qwerty > /tmp/foo": 2 events (write operation, one event for truncate operation and one for the write of "qwerty" at the beginning of the file)
read() = 16
event->len = 0
Pathname1 is modified
i=16
read() = 16
event->len = 0
Pathname1 is modified
i=16
====== Upon "echo qwerty >> /tmp/foo": 1 event (write of "qwerty" at the end of the file)
read() = 16
event->len = 0
Pathname1 is modified
i=16
If the two pathnames refer to the same inode, then inotify.wd1 == inotify.wd2. In that case, because you have
if (event->wd == inotify.wd1) {
printf("Pathname1 '%s' is modified\n", event->name);
}
if (event->wd == inotify.wd2) {
printf("Pathname2 '%s' is modified\n", event->name);
}
both bodies would be executed; but the outputs would differ (Pathname1 ... and Pathname2 ...).
You really should be monitoring the directories the files reside in, rather than the actual pathnames, so you can catch rename events also. (Many editors create a temporary file, and rename or hardlink the temporary file over the old file, so that programs see either the old or the new file, and never a mix of the two.)
Consider the following program, which does not exhibit any undue duplication of events:
// SPDX-License-Identifier: CC0-1.0
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/inotify.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
static volatile sig_atomic_t done = 0;
static void handle_done(int signum)
{
done = signum;
}
static int install_done(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0;
return sigaction(signum, &act, NULL);
}
struct monitor {
/* Supplied by caller */
const char *directory;
const char *pathname;
int (*modified)(struct monitor *);
int (*completed)(struct monitor *);
/* Reserved for internal use */
int dirwatch;
};
int monitor_files(struct monitor *const list, const size_t count)
{
char *events_ptr = NULL;
size_t events_len = 65536;
size_t i;
int err;
/* Verify sane parameters */
if (count < 1) {
errno = ENOENT;
return -1;
} else
if (!list) {
errno = EINVAL;
return -1;
}
for (i = 0; i < count; i++) {
if (!list[i].directory || !list[i].directory[0]) {
errno = EINVAL;
return -1;
}
if (!list[i].pathname || !list[i].pathname[0]) {
errno = EINVAL;
return -1;
}
list[i].dirwatch = -1;
}
/* Obtain a descriptor for inotify event queue */
int queue = inotify_init1(IN_CLOEXEC);
if (queue == -1) {
/* errno set by inotify_init1() */
return -1;
}
/* Use a reasonable dynamically allocated buffer for events */
events_ptr = malloc(events_len);
if (!events_ptr) {
close(queue);
errno = ENOMEM;
return -1;
}
/* Add a watch for each directory to be watched */
for (i = 0; i < count; i++) {
list[i].dirwatch = inotify_add_watch(queue, list[i].directory, IN_CLOSE_WRITE | IN_MOVED_TO | IN_MODIFY);
if (list[i].dirwatch == -1) {
err = errno;
close(queue);
free(events_ptr);
errno = err;
return -1;
}
}
/* inotify event loop */
err = 0;
while (!done) {
ssize_t len = read(queue, events_ptr, events_len);
if (len == -1) {
/* Interrupted due to signal delivery? */
if (errno == EINTR)
continue;
/* Error */
err = errno;
break;
} else
if (len < -1) {
/* Should never occur */
err = EIO;
break;
} else
if (len == 0) {
/* No events watched anymore */
err = 0;
break;
}
char *const end = events_ptr + len;
char *ptr = events_ptr;
while (ptr < end) {
struct inotify_event *event = (struct inotify_event *)ptr;
/* Advance buffer pointer for next event */
ptr += sizeof (struct inotify_event) + event->len;
if (ptr > end) {
close(queue);
free(events_ptr);
errno = EIO;
return -1;
}
/* Call all event handlers, even duplicate ones */
for (i = 0; i < count; i++) {
if (event->wd == list[i].dirwatch && !strcmp(event->name, list[i].pathname)) {
if ((event->mask & (IN_MOVED_TO | IN_CLOSE_WRITE)) && list[i].completed) {
err = list[i].completed(list + i);
if (err)
break;
} else
if ((event->mask & IN_MODIFY) && list[i].modified) {
err = list[i].modified(list + i);
if (err)
break;
}
}
}
if (err)
break;
}
if (err)
break;
}
close(queue);
free(events_ptr);
errno = 0;
return err;
}
static int report_modified(struct monitor *m)
{
printf("%s/%s: Modified\n", m->directory, m->pathname);
fflush(stdout);
return 0;
}
static int report_completed(struct monitor *m)
{
printf("%s/%s: Completed\n", m->directory, m->pathname);
fflush(stdout);
return 0;
}
int main(void)
{
struct monitor watch[2] = {
{ .directory = ".",
.pathname = "file1",
.modified = report_modified,
.completed = report_completed },
{ .directory = ".",
.pathname = "file2",
.modified = report_modified,
.completed = report_completed }
};
int err;
if (install_done(SIGINT) == -1 ||
install_done(SIGHUP) == -1 ||
install_done(SIGTERM) == -1) {
fprintf(stderr, "Cannot set signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
fprintf(stderr, "To stop this program, press Ctrl+C, or send\n");
fprintf(stderr, "INT, HUP, or TERM signal (to process %ld).\n", (long)getpid());
fflush(stderr);
err = monitor_files(watch, 2);
if (err == -1) {
fprintf(stderr, "Error monitoring files: %s.\n", strerror(errno));
return EXIT_FAILURE;
} else
if (err) {
fprintf(stderr, "Monitoring files failed [%d].\n", err);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
If you compile it using e.g. gcc -Wall -Wextra -O2 example.c -o example and run it via ./example, it will report IN_MODIFY events (as "Modified") and IN_CLOSE_WRITE and IN_MOVED_TO events (as "Completed") for file1 and file2 in the same directory (current working directory). To exit the program, press Ctrl+C.
(Note that we should probably add third event type, "Deleted", corresponding to IN_DELETE and IN_MOVED_FROM events.)
If you open file1 or file2 in say a text editor, saving the file generates one or more Modified (IN_MODIFY) events, and exactly one Completed (IN_CLOSE_WRITE or IN_MOVED_TO) event. This is because each open()/truncate()/ftruncate() syscall that causes the file to be truncated, generates one IN_MODIFY event for that file; as does every underlying write() syscall that modifies the file contents. Thus, it is natural to receive multiple IN_MODIFY events when some process modifies the file.
If you have multiple struct monitor entries in the list with the same effective directory and the same pathname, the example program will provide multiple events for them. If you wish to avoid this, just make sure that whenever .pathname matches, the two get differing .dirwatches.
rewriting the while() loop into a for() loop, and flattening out the if()s"
while(1){
int i ;
struct inotify_event *event ;
inotify.length = read(inotify.fd, inotify.buffer, EVENT_BUF_LEN);
for(i=0; i < inotify.length; i += EVENT_SIZE + event->len ) {
event = (struct inotify_event *)&inotify.buffer[i];
if (!event->len) continue;
if (!(event->mask & IN_MODIFY)) continue;
if (event->wd == inotify.wd1){
printf("Pathname1 '%s' is modified\n", event->name);
continue;
}
if (event->wd == inotify.wd2){
printf("Pathname2 '%s' is modified\n", event->name);
continue;
}
}
}
I'm trying to test an ncurses application in a pty. Which bytes should be sent to the pty master to trigger key codes for KEY_RESIZE, KEY_HOME, KEY_END, etc.?
There is some code posted below which I truly hope no-one ever wastes time looking at, but will include for completeness. This code behaves as follows:
$ perl -e "print pack('c', 8)" | ./wrappty ./show-key
KEY_BACKSPACE
That is, if I write 0x08 to the pty, the ncurses application treats it as a backspace. What byte sequences should be written to trigger the other key codes? I would hazard a guess that the particular byte sequence depends on the terminal, so I'm wondering if there is a standard for ptys, or if there is a reasonable method to determine the correct byte sequence.
wrappty.c:
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <unistd.h>
#ifdef __linux__
# include <pty.h>
# include <utmp.h>
#else
# include <util.h>
#endif
static void
show_data(const char *t, ssize_t s)
{
for( ; s > 0; t++, s-- ) {
const char *fmt = isprint(*t) ? "%c" : "0x%02x";
fprintf(stderr, fmt, *(unsigned char *)t);
}
fflush(stderr);
}
static ssize_t
send_msg(int fd, int b)
{
char buf[1024];
if( b != EOF ) {
write(fd, &b, 1);
}
ssize_t s;
while( (s = read(fd, buf, sizeof buf)) == sizeof buf ) {
show_data(buf, s);
}
show_data(buf, s);
return s;
}
static void
wait_for(int fd, const char *expect, size_t siz)
{
int rc = 0;
char buf[1024];
char *a = buf;
assert(siz < sizeof buf);
char *end = buf + siz;
while( a < end ) {
ssize_t s = read(fd, a, end - a);
char *e = a + s;
rc += 1;
while( a < e && *a++ == *expect++ ) {
;
}
if( s < 1 || a < e ) {
fprintf(stderr, "Ivalid data\nReceived: ");
show_data(buf, e - buf);
fprintf(stderr, "\nExpected: ");
show_data(expect, siz);
fputc('\n', stderr);
exit(1);
}
}
}
void noop(int sig, siginfo_t *i, void *v) { (void)sig; (void)i; (void)v; }
int
main(int argc, char **argv)
{
int primary, secondary, c;
struct winsize ws = { .ws_row = 24, .ws_col = 80 };
(void) argc;
if( openpty(&primary, &secondary, NULL, NULL, &ws) ) {
err(EXIT_FAILURE, "openpty");
}
switch( fork() ) {
case -1:
err(1, "fork");
break;
case 0:
if( close(primary) ) {
err(EXIT_FAILURE, "close");
}
if( login_tty(secondary) ) {
err(EXIT_FAILURE, "login_tty");
}
execvp(argv[1], argv + 1);
err(EXIT_FAILURE, "execvp %s", argv[1]);
}
/* Parent */
if( close(secondary) ) {
err(EXIT_FAILURE, "close");
}
/* Initialization sequence from ncurses on macos */
char *expected = "\x1b(B\x1b)0\x1b[?1049h\x1b[1;24r\x1b[m\x0f\x1b[4l"
"\x1b[?1h\x1b=\x1b[H\x1b[J";
struct sigaction act;
memset(&act, 0, sizeof act);
act.sa_sigaction = noop;
if( sigaction( SIGALRM, &act, NULL ) ) {
perror("sigaction");
return EXIT_FAILURE;
}
struct timeval tp = {.tv_sec = 0, .tv_usec = 500000 };
struct itimerval t = { .it_interval = tp, .it_value = tp };
setitimer(ITIMER_REAL, &t, NULL);
wait_for(primary, expected, strlen(expected));
while( (c = getchar()) != EOF ) {
send_msg(primary, c);
}
send_msg(primary, EOF);
fputc('\n', stderr);
return 0;
}
show-key.c:
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 600
#define _XOPEN_SOURCE_EXTENDED
#define _DARWIN_C_SOURCE
#include <ctype.h>
#include <curses.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
int xopen(const char *path, int flags);
void
handle(int sig, siginfo_t *i, void *v)
{
(void)i;
(void)v;
char *n = NULL;
switch(sig) {
case SIGHUP: n = "SIGHUP\n"; break;
case SIGTERM: n = "SIGTERM\n"; break;
case SIGINT: n = "SIGINT\n"; break;
}
if(n)
write(2, n, strlen(n));
return;
}
int
main(int argc, char **argv)
{
int r;
wint_t w = 0;
if( argc > 1 ) {
int fd = xopen(argv[1], O_WRONLY);
dup2(fd, STDERR_FILENO);
}
unsetenv("COLUMNS");
unsetenv("LINES");
struct sigaction act;
memset(&act, 0, sizeof act);
act.sa_sigaction = handle;
if( sigaction( SIGTERM, &act, NULL ) ) { perror("sigaction"); exit(1); }
if( sigaction( SIGINT, &act, NULL ) ) { perror("sigaction"); exit(1); }
if( sigaction( SIGHUP, &act, NULL ) ) { perror("sigaction"); exit(1); }
if( initscr() == NULL ) {
err(1, "initscr");
}
noecho();
keypad(stdscr, true);
while( (r = get_wch(&w)) != ERR ) {
char *d = NULL;
if( r == KEY_CODE_YES ) switch(w) {
case KEY_RESIZE: d = "KEY_RESIZE"; break;
case KEY_HOME: d = "KEY_HOME"; break;
case KEY_END: d = "KEY_END"; break;
case KEY_PPAGE: d = "KEY_PPAGE"; break;
case KEY_NPAGE: d = "KEY_NPAGE"; break;
case KEY_BACKSPACE: d = "KEY_BACKSPACE"; break;
case KEY_DC: d = "KEY_DC"; break;
case KEY_IC: d = "KEY_IC"; break;
case KEY_BTAB: d = "KEY_BTAB"; break;
case KEY_ENTER: d = "KEY_ENTER"; break;
case KEY_UP: d = "KEY_UP"; break;
case KEY_DOWN: d = "KEY_DOWN"; break;
case KEY_RIGHT: d = "KEY_RIGHT"; break;
case KEY_LEFT: d = "KEY_LEFT"; break;
}
if( d != NULL ) {
/*printw("(%s)", d);*/
fprintf(stderr, "%s", d);
} else {
/*printw("%lc", w);*/
fprintf(stderr, "%lc", w);
}
/*doupdate();*/
fflush(stderr);
}
endwin();
fprintf(stderr, "ERR\n");
return 0;
}
int
xopen(const char *path, int flags)
{
int f = open(path, flags);
if( f == -1 ) {
perror(path);
exit(EXIT_FAILURE);
}
return f;
}
Use tigetstr for fetching strings that correspond to the keys. Most are easily related to the curses names (which are listed in the getch manpage):
foo = tigetstr("khome"); // KEY_HOME
It would be nice to have a table, but since the naming convention is intuitive, no one seems to feel the need...
So I'm currently writing a server/client program that will take in three commands (HI, PID and GOODBYE) and process them accordingly. I seem to have run into some trouble with my use of semget() in my server.c code.
The error that I'm getting is "EEXIST", which according to the man pages, says that the key already exists (duh lol) - the thing is, I keep manually changing the key each time and it still gives me the error. Am I not understanding something here? It also seems to work fine for the client.c code. Do any of you guys have an idea as to why I'm experiencing this?
Sorry for the somewhat sloppy code, I've been smashing my head on my keyboard all night over this, I'll do my best to comment out my thought processes. Let me know if there's anything I can do to make it easier to read.
client.c:
#include "stdio.h"
#include "stdlib.h"
#include "sys/shm.h"
#include "sys/ipc.h"
#include "sys/types.h"
#include "sys/sem.h"
#include "signal.h"
#include "string.h"
#include <unistd.h>
#define MEM_KEY 99 // memory key
#define SEM_KEY 1337 // semaphore key
#define SEG_SIZE ( (size_t)100 ) // segment size
#define oops( m, x ) { perror(m); exit(x); } // for error checking
int seg_id, semset_id;
union semun{ int val; struct semid_ds* buf; ushort* array; }; // for wait and release functions
void wait_and_lock( int );
void release_lock( int );
int main()
{
char c;
key_t memKey = MEM_KEY, semKey = SEM_KEY; // not sure if this is necessary
char *memPtr;
if ((seg_id = shmget(memKey, SEG_SIZE, IPC_CREAT | 0777)) < 0) // get segment ID
oops("shmget", 1);
if ((memPtr = shmat(seg_id, NULL, 0)) == (char *) -1) // attach the memory segment
oops("shmat", 2);
semset_id = semget(semKey, 2, ( 0666 | IPC_CREAT | IPC_EXCL )); // for some reason I couldn't include this in an if-statement
// but it seems to work here in the server code
if (semset_id == -1)
oops("semset", 2.5);
wait_and_lock( semset_id ); // this function was something our teacher went over with us.
// I'm still a little confused with what it's doing.
while(1)
{
printf("enter: "); // get the commands, is there a better way of doing this?
scanf("%s", memPtr);
}
release_lock( semset_id );
while (*memPtr != '*') // not sure if this is necessary, left over from old code that I was experimenting with.
sleep(1);
shmdt( memPtr ); // detach the memory
exit(0);
}
void wait_and_lock( int semset_id )
{
union semun sem_info; // some properties
struct sembuf actions[2]; // action set, an array
actions[0].sem_num = 1; // sem[1] is n_writers
actions[0].sem_flg = SEM_UNDO; // auto cleanup
actions[0].sem_op = 0; // wait for 0
actions[1].sem_num = 0; // sem[0] is n_readers
actions[1].sem_flg = SEM_UNDO; // auto cleanup
actions[1].sem_op = 1; // incr n_readers
if ( semop( semset_id, actions, 2 ) == -1 )
oops( "semop: locking", 10 );
}
void release_lock( int semset_id )
{
union semun sem_info; // some properties
struct sembuf actions[1]; // action set
actions[0].sem_num = 0; // sem[0] is n_readers
actions[0].sem_flg = SEM_UNDO; // auto cleanup
actions[0].sem_op = -1; // decr reader country
if ( semop( semset_id, actions, 1 ) == -1 )
oops( "semop: unlocking", 10 );
}
server.c:
#include "stdio.h"
#include "stdlib.h"
#include "sys/shm.h"
#include "sys/ipc.h"
#include "sys/types.h"
#include "sys/sem.h"
#include "signal.h"
#include "string.h"
#include <unistd.h>
#define MEM_KEY 99
#define SEM_KEY 1337
#define SEG_SIZE ( (size_t)100 )
#define oops( m, x ) { perror(m); exit(x); }
union semun { int val; struct semid_ds* buf; unsigned short* array; };
int seg_id, semset_id;
void cleanup( int );
void set_sem_value( int, int, int );
void wait_and_lock( int );
void release_lock( int );
int main()
{
int id = 0;
char *memPtr;
key_t memKey = MEM_KEY, semKey = SEM_KEY;
signal( SIGINT, cleanup ); // to handle Ctrl-C
seg_id = shmget( memKey, SEG_SIZE, 0777 ); // get segment ID
if( seg_id == -1 )
oops( "shmget", 1 );
if ((memPtr = shmat(seg_id, NULL, 0)) == (char *) -1) // attach to memPtr
oops("shmat",2);
semset_id = semget( semKey, 2, ( 0666 | IPC_CREAT | IPC_EXCL ) );
// this is where there seems to be an issue? This is where the code stops.
if ( semset_id == -1 )
oops( "semget", 3 );
set_sem_value( semset_id, 0, 0 ); // set counters
set_sem_value( semset_id, 1, 0 ); // both to zero
//Now read what the client put in the memory (still not sure if this works
//because the program hasn't technically gotten that far. So this while loop is more
//of a prototype).
while(1)
{
wait_and_lock( semset_id );
printf( "\tshm_ts2 update memory\n" ); // will be removed at the end
sleep(1);
if(strcmp(memPtr, "HI")==0) // look for HI
{
printf("Greetings!\n"); // print this to the server screen
fflush(stdout);
memPtr[0] = '\0';
}
else if(strcmp(memPtr, "PID")==0) // look for PID and get server's PID
{
id = (int)getpid();
printf("Server pid: %i\n", id);
fflush(stdout);
memPtr[0] = '\0';
}
else if(strcmp(memPtr, "QUIT")==0){ // check for quit
shmctl(seg_id, IPC_RMID, NULL); // mark seg to be destroyed
shmdt(memPtr); // detach segment
printf("GOODBYE!\n");
exit(0);
}
release_lock( semset_id );
printf( "\tshm_ts2 released lock\n" ); // will be removed at the end
}
*memPtr = '*'; // still not sure if this is necessary, from old code
cleanup(0);
return 0;
}
void cleanup( int n )
{
shmctl( seg_id, IPC_RMID, NULL );
semctl( semset_id, 0, IPC_RMID, NULL );
}
void set_sem_value( int semset_id, int semnum, int val )
{
union semun initval;
initval.val = val;
if ( semctl( semset_id, semnum, SETVAL, initval ) == -1 )
oops( "semctl", 4 );
}
void wait_and_lock( int semset_id )
{
struct sembuf actions[2]; // action set, an array
actions[0].sem_num = 0; // sem[0] is n_readers
actions[0].sem_flg = SEM_UNDO; // auto cleanup
actions[0].sem_op = 0; // wait til no readers
actions[1].sem_num = 1; // sem[1] is n_writers
actions[1].sem_flg = SEM_UNDO; // auto cleanup
actions[1].sem_op = 1; // increment number of writers
if ( semop( semset_id, actions, 2 ) == -1 )
oops("semop: locking", 10 );
}
// Thing 4: build and execute a 1-element action set: decrement num_writers
void release_lock( int semset_id )
{
struct sembuf actions[1]; // action set, an array
actions[0].sem_num = 1; // sem[0] is n_writers
actions[0].sem_flg = SEM_UNDO; // auto cleanup
actions[0].sem_op = -1; // decrement number of writer count
if ( semop( semset_id, actions, 1 ) == -1 )
oops( "semop: unlocking", 10 );
}
You need to make a system V IPC key using the ftok function. Than, that key should be passed as the first parameter to the shmget system call. The same applies to semaphores. Make a System V IPC key using ftok and pass it as the first parameter to semget.
I have a problem with the compiling of my program, when I test something like "./philo -p 3 -e 4" I get the error
philo: tpp.c:62: __pthread_tpp_change_priority: Assertion `new_prio == -1 || (new_prio >= __sched_fifo_min_prio && new_prio <= __sched_fifo_max_prio)' failed.
Aborted
But I don't understand where it does come from, as it's working sometimes, for exemple if I test "./philo -p 2 -e 4" it doesn't crash.
The two .h
#ifndef _PHILO_H_
# define _PHILO_H_
#include <pthread.h>
typedef struct s_philosop
{
pthread_t philosophers;
pthread_mutex_t *chopsticks1;
pthread_mutex_t *chopsticks2;
int nbr_occ;
} t_philosop;
int parse_arg(char **argv, int *philo, int *occ);
int create_threads_mutex(int nbr_philo, int occurences);
void *start_routine(void *arg);
void philosoph_eating_chopsticks(t_philosop *philosop);
#endif /* !_PHILO_H_ */
#ifndef __LIBRICEFEREE_EXTERN__
# define __LIBRICEFEREE_EXTERN__
#include <pthread.h>
int RCFStartup(int ac, char **av);
void RCFCleanup();
int lphilo_eat();
int lphilo_sleep();
int lphilo_think();
int lphilo_take_chopstick(const pthread_mutex_t *mutex_id);
int lphilo_release_chopstick(const pthread_mutex_t *mutex_id);
#endif /* __LIBRICEFEREE_EXTERN__ */
And this is my .c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "philo.h"
#include "extern.h"
void philosoph_comportement(t_philosop *philosop)
{
int i = 0;
if ((pthread_mutex_lock(philosop->chopsticks1)) == 0)
{
printf("%s\n", "Taking left stick");
lphilo_take_chopstick(philosop->chopsticks1);
i++;
}
if ((pthread_mutex_lock(philosop->chopsticks2)) == 0)
{
printf("%s\n", "Taking right stick");
lphilo_take_chopstick(philosop->chopsticks2);
i++;
}
if (i == 2)
{
printf("%s\n", "Eat");
lphilo_eat();
sleep(1);
printf("%s\n", "Sleep");
pthread_mutex_unlock(philosop->chopsticks1);
pthread_mutex_unlock(philosop->chopsticks2);
lphilo_release_chopstick(philosop->chopsticks1);
lphilo_release_chopstick(philosop->chopsticks2);
lphilo_sleep();
}
}
void *start_routine(void *arg)
{
t_philosop *philosop;
int i;
i = 0;
philosop = (t_philosop *)arg;
while (i != philosop->nbr_occ)
{
philosoph_comportement(philosop);
i++;
}
return (0);
}
int create_threads_mutex(int nbr_philo, int occurences)
{
int i;
t_philosop *philosop;
pthread_mutex_t *chopsticks;
i = -1;
if ((chopsticks = malloc(sizeof(pthread_mutex_t) * nbr_philo)) == NULL)
return (2);
if ((philosop = malloc(sizeof(t_philosop) * nbr_philo)) == NULL)
return (2);
while (++i != nbr_philo)
{
philosop[i].nbr_occ = occurences;
philosop[i].chopsticks1 = &chopsticks[i];
if (i - 1 < 0)
philosop[i].chopsticks2 = &chopsticks[nbr_philo];
else
philosop[i].chopsticks2 = &chopsticks[i - 1];
}
i = -1;
while (++i != nbr_philo)
pthread_create(&philosop[i].philosophers, NULL, start_routine, &philosop[i]);
i = -1;
while (++i != nbr_philo)
{
printf("Philo number : %d\n", i);
pthread_join(philosop[i].philosophers, NULL);
}
return (0);
}
int parse_arg(char **argv, int *philo, int *occ)
{
if (strcmp(argv[1], "-p") == 0 && strcmp(argv[3], "-e") == 0 &&
argv[2] != NULL && argv[4] != NULL)
{
*philo = atoi(argv[2]);
*occ = atoi(argv[4]);
}
else if (strcmp(argv[1], "-e") == 0 && strcmp(argv[3], "-p") == 0 &&
argv[2] != NULL && argv[4] != NULL)
{
*philo = atoi(argv[4]);
*occ = atoi(argv[2]);
}
else
return (2);
return (0);
}
int main(int argc, char **argv)
{
int philo;
int occurences;
philo = 0;
occurences = 0;
if (argc != 5)
return (2);
if ((parse_arg(argv, &philo, &occurences)) == 2)
return (2);
RCFStartup(argc, argv);
if ((create_threads_mutex(philo, occurences)) == 2)
return (2);
RCFCleanup();
return (0);
}
You don't initialize any of your mutexes with pthread_mutex_init.
And assuming lphilo_release_chopstick does nothing but unlock a mutex, this code is wrong as it will try to unlock each mutex twice:
pthread_mutex_unlock(philosop->chopsticks1);
pthread_mutex_unlock(philosop->chopsticks2);
lphilo_release_chopstick(philosop->chopsticks1);
lphilo_release_chopstick(philosop->chopsticks2);
I am having a problem with my Consumer, producer program, it seems to load, but returns a segmentation error. I have tried everything to fix it but still failing!! Will be greatful for any assistance.
Note; The code is really much, semaphore.h code is within, if anyone wishes to test. and the rest of the code is as is here. Am runing this on a Unix machine.
//----------------SEMOPHORE.H--------------------------
/*********************** semaphore.h ****************************/
#define SEM_NAME "semaphore.h",'a'
#define SEM_MAX 3
#define FREE 0
#define DATA 1
#define ROOM 2
#define S_WAIT -1
#define S_SIGNAL 1
#define NO_EVENT -1
int sem_config(int, int);
int sem_wait(int, int);
int sem_signal(int, int);
//----------------Producer-----------------------
#include<stdio.h>
#include"semaphore.h"
#include"shbuf.h"
# include <string.h>
# include "shbuf.h"
void myadd();
main()
{
sem_config(DATA, FREE);
myadd();
sem_signal(DATA,S_SIGNAL);
return 0;
}
void myadd()
{
char str[80];
char discard;
printf("you can type a message for the producer."\n);
printf("Producing message : ");
scanf("%s%c", str, &discard);
q_add(strlen(str) , str);
}
//---------------------------CONSUMER---------------------------
#include<stdio.h>
#include"semaphore.h"
#include"shbuf.h"
# include <string.h>
# include "shbuf.h"
void myremove();
main()
{
sem_wait(DATA, S_WAIT);
myremove();
sem_signal(DATA,S_SIGNAL);
return 0;
}
void myremove()
{
char str[80];
if(q_items() > 0)
{
q_remove(1 , str);
str[1] = 0;
printf("%s\n", str);
}
}
//-------------------------------SEMAPHORE.C--------------------------------------
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include "semaphore.h"
static int sem_id;
static union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
ushort array[1]; /* array for GETALL & SETALL, used in setting or retrieving all semaphorevalues in a set.*/
} sem_attr;
static struct sembuf asem[1];
static key_t s_key; //key for shared memory
int sem_config(int event, int init_val)
{
int x;
s_key = ftok(SEM_NAME); //key for semaphore
//create a semaphore for process synchronization
if ( -1 == (sem_id = semget(s_key, SEM_MAX, 0666|IPC_CREAT ) ))
{
perror("semget");
return -1;
}
if ( event == NO_EVENT )
return 0; /*locate semaphore only*/
//set initial value of semaphore
sem_attr.val = init_val;
if ( -1 == semctl(sem_id, event, SETVAL, sem_attr ) )
{
perror("semctl SETVAL");
return -1;
}
if ( -1 == ( x = semctl(sem_id, event, GETVAL, sem_attr ) ) )
{
perror("semctl GETVAL");
return -1;
}
assert( x == init_val );
return 0;
}
int sem_wait(int event, int nwaits)
{
asem[0].sem_num = event;
asem[0].sem_op = nwaits * S_WAIT;
asem[0].sem_flg = 0;
if ( event == NO_EVENT ) /*remove semaphore set*/
if ( -1 == semctl(sem_id, 0, IPC_RMID, sem_attr ) )
{
perror("semctl IPC_RMID");
return -1;
}
else
return 0;
if ( -1 == semop(sem_id, asem, 1 ) )
{
perror("semop");
return -1;
}
return 0;
}
int sem_signal(int event, int nsignals)
{
asem[0].sem_num = event;
asem[0].sem_op = nsignals * S_SIGNAL;
asem[0].sem_flg = 0;
if ( event == NO_EVENT )
if ( -1 == semctl(sem_id, 0, IPC_RMID, sem_attr ) )
{
perror("semctl IPC_RMID");
return -1;
}
else
return 0;
if ( -1 == semop(sem_id, asem, 1 ) )
{
perror("semop");
return -1;
}
return 0;
}
In general, the best way to debug segmentation faults is by compiling with the -g flag and running in a debugger like gdb. It will tell you exactly where it is crashing and let you print out the values of variables to tell you why.
Compile with debugging symbols. If you're using gcc then use the -g3 flag for the most symbols. You should also be using the -Wall flag and pay attention to the warnings it gives you. Try stepping trough the program that fails first with a debugger and see where it fails.
My bet is that the problem is in your q_remove and q_add code because that's the code you left out, and because it probably uses arrays.