This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug sanitizer/55561] TSAN crashes for Fortran


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55561

--- Comment #12 from Dmitry Vyukov <dvyukov at google dot com> 2012-12-10 15:07:11 UTC ---
(In reply to comment #11)
> (In reply to comment #10)
> > Is is a correct report? Or false positive?
> 
> This is a correct report for the testcase in comment #0 (as J is shared between
> threads).

That's great that gcc tsan works for Fortran/OpenMP out of the box!

However, most likely Fortran/OpenMP will require some special handling to
produce better reports and catch more bugs (ThreadSanitizer reasons about
synchronization on pthread level, and not on OpenMP level). We won't have spare
cycles for that in near future.
I am working on ThreadSanitizer tasking API, I would appreciate if you review
it and comment on whether it will fit Fortran/OpenMP model (the work is
currently in very early "what if" stage).
The is the proposed public API:


// The tasking API is intended for programs that use finer-grained tasks
// on top of threads.  For such programs ThreadSanitizer can produce
// bad reports (namely, thread creation stack is useless), and catch less
// bugs because it does not understand task boundaries.
// The tasking API allows programs to annotate tasks to solve both problems.
// The API is intended to be flexible enough to support standard C++ tasks,
// OpenMP tasks as well as custom tasks.  It's also intended to be
// non-intrusive as possible to be used merely as annotations in existing code.

// Creation of a task.
// TASK is an arbitrary pointer that uniquely identifies the task.
// ThreadSanitizer stores any required internal info offline.
// FLAGS see below.
void __tsan_task_create(void *task, unsigned flags);

// Destruction of a task, frees all associated resources.
// After that the TASK pointer can be reused for another task.
void __tsan_task_destroy(void *task);

// Denotes beginning of execution of the TASK.
// When the function returns ThreadSanitizer effectively switches
// to another thread context associated with the task.
// Returns TASK.  This is needed because re-reading it even from stack variable
// can result in a data race with the worker thread (since we are already in
the
// task context).
// Tasks can be recursive, but must be strictly nested.
void* __tsan_task_begin(void *task);

// Denotes end of execution of the TASK.
// When the function returns ThreadSanitizer effectively switches
// back to worker thread context.
void __tsan_task_end(void *task);

// If set, ThreadSanitizer uses separate thread context for task execution.
// If not set, ThreadSanitizer can not detect any new data races but still
// produces better reports (namely, task creation stack).  A user may not want
// to set in two cases:
// 1. If task executor executes tasks in single thread (and that is the part
//    of public contract).
// 2. If ThreadSanitizer produces false postives, but a user still wants
//    to take advantage of better reports.
const unsigned __TSAN_TASK_FLAG_SYNC = 1 << 0;

// Denotes that the task is periodic, i.e. can be executed several times
// (intended for periodic timer tasks and IO rediness notifications).
// If set, then __tsan_task_begin()/__tsan_task_end() can be called several
// times.  After the last execution the task must be explicitly destroyed with
// __tsan_task_destroy().
const unsigned __TSAN_TASK_FLAG_PERIODIC = 1 << 1;

// Usage examples:
/*
1. Non-prdiodic task:

void ThreadPool::Add(Task *t) {
  __tsan_task_create(t, __TSAN_TASK_FLAG_SYNC);
  mutex_.lock();
  queue_.push_back(t);
  mutex_.unlock();  
}

void ThreadPool::WorkerThread() {
  for (;;) {
    mutex_.lock();
    while (queue_.empty())
      convvar_.wait(&mutex_);
    Task *t = queue_.pop_front();    
    mutex_.unlock();
    t = __tsan_task_begin(t);
    t->Execute();
    __tsan_task_end(t);
    __tsan_task_destroy(t);
    delete t;
  }
}

This is semantically equivalent to:

void ThreadPool::Add(Task *t) {
  pthread_create(&t->thread_, 0, &Task::Execute, t);
}

2. Priodic task:

void ThreadPool::AddPeriodic(Task *t) {
  __tsan_task_create(t, __TSAN_TASK_FLAG_SYNC | __TSAN_TASK_FLAG_PERIODIC);
  AddPeriodicImpl(t, t->Period());
}

void ThreadPool::WorkerThread() {
  for (;;) {
    Task* t = CheckPeriodicTasks();
    if (t) {
      t = __tsan_task_begin(t);
      t->Execute();
      __tsan_task_end(t);
      AddPeriodicImpl(t, t->Period());
    }
    ...
  }
}

void ThreadPool::CancelPeriodic(Task *t) {
  CancelPeriodicImpl(t);
  __tsan_task_destroy(t);
  delete t;
}

This is semantically equivalent to:

void ThreadPool::Add(Task *t) {
  pthread_create(&t->thread_, 0, &ExecutePeriodic, t);
}

void *ExecutePeriodic(Task *t) {
  while (!t->Cancelled()) {
    sleep(t->Period());
    t->Execute();
  }
}

void ThreadPool::CancelPeriodic(Task *t) {
  t->SetCancelled();
  pthread_join(t->thread_, 0);
  delete t;
}
*/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]