Hello!
My friend find some stranges in FreeBSD threads implementation...
Here is a "special" code:

=====================================
#include <stdio.h>
#include <assert.h>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

#define Debug(x)        printf x

extern "C" {
typedef void *(*_THR_C_FUNC)(void *args);
}
typedef void *(*_THR_FUNC)(void *args);

/*-----------------------------------------------------------------*/
class    Mutex
{
public:
  Mutex() { assert(::pthread_mutex_init(&this->lock_, 0) == 0); }
  ~Mutex (void) { assert(::pthread_mutex_destroy(&this->lock_)==0); }
  int acquire (void) { return ::pthread_mutex_lock(&this->lock_); }
  int release (void) { return ::pthread_mutex_unlock (&this->lock_); }
  pthread_mutex_t lock_;
};

/*-----------------------------------------------------------------*/
class Condition
{
public:
  Condition (Mutex &m);
  ~Condition (void);
  int wait (void);
  void signal (void);
protected:
  pthread_cond_t cond_;
  Mutex &mutex_;
};

Condition::Condition (Mutex &m) : mutex_ (m)
{
  assert (pthread_cond_init(&this->cond_, 0) == 0);
}

Condition::~Condition (void)
{
   
    while(::pthread_cond_destroy(&this->cond_) == -1 && errno == EBUSY)
      {
        assert(::pthread_cond_broadcast(&this->cond_) == 0);
#ifdef __linux__
        ::sched_yield ();
#else
        ::pthread_yield();
#endif
      }
}

int Condition::wait (void)
{
  return ::pthread_cond_wait(&this->cond_, &this->mutex_.lock_);
}

void Condition::signal (void)
{
  assert(::pthread_cond_signal(&this->cond_) == 0);
}

/*-----------------------------------------------------------------*/
class Guard
{
public:
  Guard (Mutex &l);
  ~Guard (void);
private:
  Mutex *lock_;
};
Guard::Guard (Mutex &l)
  : lock_ (&l)
{
  this->lock_->acquire ();
}
Guard::~Guard (void)
{
  this->lock_->release ();
}

/*-----------------------------------------------------------------*/
class _Base_Thread_Adapter
{
public:
  _Base_Thread_Adapter (_THR_FUNC user_func, void *arg);
  void *invoke (void);
  _THR_C_FUNC entry_point (void) { return entry_point_; }

private:
  _THR_FUNC user_func_;
  void *arg_;
  _THR_C_FUNC entry_point_;
};

extern "C" void * _thread_adapter (void *args)
{
  _Base_Thread_Adapter *thread_args = (_Base_Thread_Adapter*)args;
  void *status = thread_args->invoke ();
  return status;
}

_Base_Thread_Adapter::_Base_Thread_Adapter (_THR_FUNC user_func, void *arg)
  : user_func_ (user_func), arg_ (arg), entry_point_ (_thread_adapter)
{
}

void *
_Base_Thread_Adapter::invoke (void)
{
  void *(*func)(void *) = this->user_func_;
  void *arg = this->arg_;
  delete this;
  return func(arg);
}

/*-----------------------------------------------------------------*/
class SS {
  public:
    void spawn();
    static void run();
    static void *WThread( void *data );
};
  
/*---------------------------------------------------------------------*/
static Mutex CMutex;
static Condition Cond(CMutex);
static Mutex m1;

/*---------------------------------------------------------------------*/
#define REL(m,n) assert(m.release() != -1)
#define ACQ(m,n) assert(m.acquire() != -1)
      
/*---------------------------------------------------------------------*/
void *
SS::WThread( void *data )
{
    Cond.signal();
    Debug(("run thread...\n"));
    SS::run();
    Debug(("thread ended\n"));
    return NULL;
}

/*---------------------------------------------------------------------*/
int thr_create (_THR_FUNC func, void *args)
{
  _Base_Thread_Adapter *thread_args;
  thread_args  = new  _Base_Thread_Adapter(func, args);
  pthread_attr_t attr;
  if (::pthread_attr_init (&attr) != 0)
      return -1;
  ::pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  pthread_t thr_id;
  assert( ::pthread_create (&thr_id, &attr,
                    thread_args->entry_point(), thread_args) == 0 );
  ::pthread_attr_destroy (&attr);
}
/*---------------------------------------------------------------------*/
void
SS::spawn()
{
#ifdef BAD
    int rc;
    Guard guard(m1);   // !!!
#else
    Guard guard(m1);   // !!!
    int rc;
#endif
    pthread_attr_t attr;
    if (::pthread_attr_init (&attr) != 0) return;
    ::pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    thr_create(SS::WThread, (void *)0);
    ::pthread_attr_destroy (&attr);
    ACQ(CMutex, "CMutex");
    rc = Cond.wait();
    if( rc == -1 )
      Debug(("Cond wait failed: %s\n", strerror(errno)));
    REL(CMutex, "CMutex"); 
}

/*---------------------------------------------------------------------*/
void
SS::run()
{
    string s;   // !!!
    string s1;  // !!!
    sleep(1);
}

/*=====================================================================*/
static void sp_call(SS *ss)
{
    string s;   // !!!
    ss->spawn();
}

/*------------------------------------------------------------------*/
int main(int argc, char **argv)
{
    SS ss;
    sp_call(&ss);
    sleep(2);
    Debug(("Exitting...\n"));
    sleep(3);
    return 0;
}
=====================================

and here is is a makefile (use gmake for build):

=====================================
Goal: bad good

bad: tt.cpp
        $(CXX) -DBAD tt.cpp -pthread  -g -o bad

good: tt.cpp
        $(CXX) tt.cpp -pthread  -g -o good
=====================================

After build code, try run ./good and ./bad:

=====================================
$ ./good
run thread...
thread ended
Exitting...
$ ./bad
run thread...
zsh: segmentation fault (core dumped)  ./bad
$
=====================================
Thats stranges work in FreeBSD 4.2-STABLE #0: Wed Nov 22 19:25:46 MSK 2000
and FreeBSD 5.0-CURRENT #0: Wed Nov 22 01:23:44 MSK 2000

Any idea?
Make send-pr?

Sergey Osokin,
[EMAIL PROTECTED]


To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to