/* Generated by Frama-C */
typedef void *framac_mthread_name;
typedef int framac_mthread_id;
typedef framac_mthread_id pthread_t;
typedef framac_mthread_id pthread_attr_t;
typedef framac_mthread_id pthread_mutex_t;
typedef framac_mthread_id pthread_mutexattr_t;
typedef int msgqueue_t;
extern int __FRAMAC_MTHREAD_SHARED;
int __FRAMAC_MTHREAD_THREADS_RUNNING = 0;
int __FRAMAC_MTHREAD_THREADS[16];
int __FRAMAC_MTHREAD_MUTEXES[16];
int __FRAMAC_MTHREAD_QUEUES[16];
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern framac_mthread_id __FRAMAC_THREAD_CREATE(framac_mthread_name,
                                                void *(*)(void *) , ...);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern int __FRAMAC_THREAD_START(framac_mthread_id);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern int __FRAMAC_THREAD_SUSPEND(framac_mthread_id);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern int __FRAMAC_THREAD_CANCEL(framac_mthread_id);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern framac_mthread_id __FRAMAC_THREAD_ID();
/*@ terminates \false;
    ensures \false;
    assigns __FRAMAC_MTHREAD_SHARED;  */
extern void __FRAMAC_THREAD_EXIT(void *);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern framac_mthread_id __FRAMAC_MUTEX_INIT(framac_mthread_name);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern int __FRAMAC_MUTEX_LOCK(framac_mthread_id);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern int __FRAMAC_MUTEX_UNLOCK(framac_mthread_id);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern framac_mthread_id __FRAMAC_QUEUE_INIT(framac_mthread_name, int);
/*@ requires \valid(buf+(0..size-1));
    assigns __FRAMAC_MTHREAD_SHARED;  */
extern int __FRAMAC_MESSAGE_SEND(framac_mthread_id id, char const *buf,
                                 int size);
/*@ requires \valid(buf+(0..size-1));
    assigns *buf, __FRAMAC_MTHREAD_SHARED;
    assigns *buf \from \empty;
  
*/
extern int __FRAMAC_MESSAGE_RECEIVE(framac_mthread_id, int size, char *buf);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern void __FRAMAC_MTHREAD_SHOW(char const * , ...);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern void __FRAMAC_MTHREAD_NAME_THREAD(framac_mthread_id,
                                         framac_mthread_name);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern void __FRAMAC_MTHREAD_NAME_MUTEX(framac_mthread_id,
                                        framac_mthread_name);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern void __FRAMAC_MTHREAD_NAME_QUEUE(framac_mthread_id,
                                        framac_mthread_name);
/*@ assigns __FRAMAC_MTHREAD_SHARED;  */
extern void __FRAMAC_MTHREAD_SYNC();
int end2 = 0;
pthread_mutex_t locks[5];
pthread_t jobs[5];
msgqueue_t queue;
/*@ assigns \at(\result,Post) \from \nothing;  */
extern int random();
void aux(int l, int r, int mess)
{
  int tmp;
  pthread_mutex_lock(& locks[l]);
  pthread_mutex_lock(& locks[r]);
  tmp = random();
  if (tmp) {
    if (mess != 2) {
      char buf[2];
      buf[0] = (char)mess;
      end2 = 1;
      msgsnd(queue,(char const *)(buf),2);
    }
  }
  pthread_mutex_unlock(& locks[r]);
  pthread_mutex_unlock(& locks[l]);
  return;
}

void *job(void *k)
{
  void *__retres;
  int p;
  int l;
  int tmp;
  int r;
  int tmp_0;
  p = (int)k;
  if (p > 0) { tmp = p - 1; }
  else { tmp = 5 - 1; }
  l = tmp;
  if (p < 5 - 1) { tmp_0 = p + 1; }
  else { tmp_0 = 0; }
  r = tmp_0;
  while (1) { aux(l,r,p + 1); }
  return (__retres);
}

int main(void)
{
  int __retres;
  int i;
  char end[2];
  end[0] = (char)0;
  i = 0;
  while (1) {
    if (! (i < 5)) { break; }
    pthread_mutex_init(& locks[i],(pthread_mutexattr_t *)((void *)0));
    i ++;
  }
  queuecreate((framac_mthread_name *)(& queue),5);
  i = 0;
  while (1) {
    if (! (i < 5)) { break; }
    pthread_create(& jobs[i],(pthread_attr_t const *)((void *)0),& job,
                   (void *)i);
    i ++;
  }
  while (1) {
    if (end[0]) {
      __FRAMAC_MTHREAD_SYNC();
      if (end2) { break; } }
    msgrcv(queue,2,end);
  }
  __retres = 0;
  return (__retres);
}

int pthread_create(pthread_t *thread, pthread_attr_t const *attr,
                   void *(*start_routine)(void *), void *arg)
{
  int __retres;
  int result;
  result = __FRAMAC_THREAD_CREATE((void *)thread,start_routine,arg);
  if (result > 0) {
    *thread = result;
    __FRAMAC_THREAD_START(result);
    __retres = 0;
    goto return_label;
  }
  else {
    __retres = 11;
    goto return_label; }
  return_label: /* internal */ 
  return (__retres);
}

int pthread_cancel(pthread_t thread)
{
  int result;
  int tmp_0;
  result = __FRAMAC_THREAD_CANCEL(thread);
  if (result != -1) { tmp_0 = 0; }
  else { tmp_0 = 3; }
  return (tmp_0);
}

pthread_t pthread_self(void)
{
  pthread_t tmp;
  tmp = __FRAMAC_THREAD_ID();
  return (tmp);
}

int pthread_mutex_init(pthread_mutex_t * __restrict mutex,
                       pthread_mutexattr_t const * __restrict attr)
{
  int __retres;
  int result;
  result = __FRAMAC_MUTEX_INIT((void *)mutex);
  if (result > 0) {
    *mutex = result;
    __retres = 0;
    goto return_label; }
  else {
    __retres = 22;
    goto return_label; }
  return_label: /* internal */ 
  return (__retres);
}

int pthread_mutex_lock(pthread_mutex_t *mutex)
{
  int result;
  int tmp_0;
  result = __FRAMAC_MUTEX_LOCK(*mutex);
  if (result != -1) { tmp_0 = 0; }
  else { tmp_0 = 22; }
  return (tmp_0);
}

int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
  int result;
  int tmp_0;
  result = __FRAMAC_MUTEX_LOCK(*mutex);
  if (result != -1) { tmp_0 = 0; }
  else { tmp_0 = 22; }
  return (tmp_0);
}

int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
  int result;
  int tmp_0;
  result = __FRAMAC_MUTEX_UNLOCK(*mutex);
  if (result != -1) { tmp_0 = 0; }
  else { tmp_0 = 22; }
  return (tmp_0);
}

void pthread_exit(void *thread_return)
{
  __FRAMAC_THREAD_EXIT(thread_return);
  return;
}

int volatile NON_DET_JOIN;
int pthread_join(pthread_t thread, void **thread_return)
{
  int tmp;
  *thread_return = (void *)NON_DET_JOIN;
  if (NON_DET_JOIN) { tmp = -1; }
  else { tmp = 0; }
  return (tmp);
}

int pthread_setcancelstate(int state, int *oldstate)
{
  int __retres;
  __retres = 0;
  return (__retres);
}

int pthread_setcanceltype(int type, int *oldtype)
{
  int __retres;
  __retres = 0;
  return (__retres);
}

void pthread_testcancel(void)
{
  return;
}

int queuecreate(framac_mthread_name *q, int size)
{
  int __retres;
  *((int *)q) = __FRAMAC_QUEUE_INIT((void *)q,size);
  __retres = 0;
  return (__retres);
}

int msgsnd(int msgqid, char const *mess, int size)
{
  int result;
  result = __FRAMAC_MESSAGE_SEND(msgqid,mess,size);
  return (result);
}

int msgrcv(int msgqid, int size, char *mess)
{
  int tmp;
  tmp = __FRAMAC_MESSAGE_RECEIVE(msgqid,size,mess);
  return (tmp);
}