views:

272

answers:

3

Hi everyone:

This is my first attempt on semaphores and threads. I constructed this code from examples and the man pages found on the Net. I have two doubts with this code.

  1. Why do I get a Bus error whenever I try semctl( I know this is the root of the problem because of the debug line 3 does not get printed) and how to prevent it?

  2. Why am I not able to acquire a lock on my critical section inspite of removing semctl()?

I am trying to execute the following code:

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>

#define NUM 3
char c='a';
int semId=-1;
struct sembuf lockOperation = { 0, -1, 0};
struct sembuf unlockOperation = { 0, -1, 0};

void* PrintLetter()
{
  int rc;

  rc=semop(semId, &lockOperation, 1);

  if(rc)
    {
      printf("\n Unable to lock\n");
      exit(1);
    }
  printf("%c",c);    //CRITICAL SECTION
  c=c+1;             //CRITICAL SECTION  
  rc = semop(semId, &unlockOperation, 1);
  if(rc)
    {
      printf("\n Unable to unlock\n");
      exit(1);
    }

  pthread_exit(NULL);

}
int main()
{
  pthread_t threads[NUM];

  int rc=1;
  long t;
   printf("debug line 1\n");
  semId = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL);
  if( semId == -1)
    {
      printf("\n Error in making the sem\n");
      exit(1);
    }
  printf("debug line 2\n");
  rc = semctl(semId, 0, SETVAL, (int)1); // Comment from here

  if(rc)
    {
      printf("\n Unable to set val to 1\n");
      exit(1);
      }    ////////////////////////////////// till here
   printf("debug line 3\n");


  for(t=0; t<NUM; t++){
    printf("In main: creating thread %ld\n", t);
    rc = pthread_create(&threads[t], NULL, PrintLetter, NULL);
    if (rc){
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
    }
    sleep(3);
  }
  pthread_exit(NULL);
}

NOTE: I added the following to the code after suggestion:

union semun {
  int              val;    /* Value for SETVAL */
  struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
  unsigned short  *array;  /* Array for GETALL, SETALL */
  struct seminfo  *__buf;  /* Buffer for IPC_INFO
                              (Linux specific) */
};

Also added the following:

union semun s_u;
s_u.val=1;

Changed the semctl line to

rc = semctl(semId, 0, SETVAL, s_u);

and made all rc checks to:

if(rc == -1)

semctl() line still does not execute sucessfully. The errno now states : Permission Denied

UPDATE: I am able to get rid off the "Permission Denied" error using the following change:

semId = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL|0660);

Now , the new problem is that, I am unable to print "abc" on the console. The program just prints "a" and hangs. Not sure why.

Final UPDATE: I messed up in the Unlock code: i used -1 instead of 1 Here is the new code:

struct sembuf unlockOperation = { 0, 1, 0};

I thank you all for your help and patience.

A: 

hi

Try to pass explicit semun union to semctl, rather than rvalue 1. probably should not matter, but who knows.

aaa
+3  A: 

The fourth argument to semctl (if present) should be of type union semun:

union semun {
            int val;
            struct semid_ds *buf;
            unsigned short  *array;
} arg;

Maybe passing an int there instead is causing alignment problems.

Alex Martelli
could be due to 32-bit int, 64-bit pointer.
aaa
@Alex: I tried adding the following lines: union semun s_u; s_u.val=1; rc = semctl(semId, 0, SETVAL, s_u);I get the following error:sem.c:42: error: storage size of 's_u' isn't known
tomkaith13
@tomkaith, that error message tells you that you have not read (or understood) the manual page, see http://docs.sun.com/app/docs/doc/816-5167/semctl-2?a=view : """type union semun, which must be explicitly declared by the application program.""" -- **explicitly declared by the application**, get it?
Alex Martelli
@Alex: Thanks for that. I defined the union now .. But my semctl() still fails with the "Unable to set val to 1" message. Any idea on why I am unable to set this the sem val ?
tomkaith13
See also the POSIX standard (http://www.opengroup.org/onlinepubs/9699919799/toc.htm) which says the same thing. It is a weirdness imposed on POSIX by a weirdness in the original System V IPC implementation. I can't think of any other type in POSIX that the user must use but must also define.
Jonathan Leffler
What is the value of 'rc' when the error message is generated. If it is failing, it should be -1 and errno should tell you more.
Jonathan Leffler
@Jonathan: Thanks.I kinda expected it be be present in the header files myself since this is my first try at semaphores. I am still unable to get the semctl() to run successfully.
tomkaith13
@ Jonathan: The errno says "ERROR: Permission denied". Is this because I dont have root privileges?? I am working on this problem in a University lab machine. I dont think i can get 'su' access
tomkaith13
@tomkaith13 - Type "ipcs -s". If you see semaphores with your userid then they were created and should show the permissions.
Duck
@Duck: This is the output from the ipcs -s line:s 53 0 ----------- btk07100 sn
tomkaith13
@tomkaith13: see the man page for semget() (http://www.opengroup.org/onlinepubs/9699919799/functions/semget.html) where it says: "Upon creation, the semid_ds data structure associated with the new semaphore identifier is initialized as follows:* In the operation permissions structure sem_perm.cuid, sem_perm.uid, sem_perm.cgid, and sem_perm.gid shall be set equal to the effective user ID and effective group ID, respectively, of the calling process.* The low-order 9 bits of sem_perm.mode shall be set equal to the low-order 9 bits of semflg."I suspect you have zeroes, leading to EPERM.
Jonathan Leffler
And I previously intended to point you to the semctl() information at http://www.opengroup.org/onlinepubs/9699919799/functions/semctl.html. Apologies for the not-as-helpful-as-intended URL.
Jonathan Leffler
+1  A: 

Before you do anything else, correct your error handling code. This is wrong:

rc = semop(semId, &lockOperation, 1);

if (rc)
{
    printf("\n Unable to lock\n");
    exit(1);
}

Semop() and semctl() return -1 on error so it should be something like

rc = semctl(semId, 0, SETVAL, (int)1); // Comment from here

if (rc == -1)
{
    perror("SETVAL");
    exit(1);
}

This get confusing because the pthread API returns 0 on success and an error number otherwise. It is easy to get them confused so be careful.

Duck
@Duck: Thank you for that advice .. I changed my code appropriately. will keep it in mind next time.
tomkaith13