blob: 58e3c7c1bc3e23acc859fb4d6793ee9e04df4eb4 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
#include "Platform.h"
#include "ExSMTaskList.h"
#include "ExSMTask.h"
#include "ExSMTrace.h"
const int EXSM_DEFAULT_NUM_BUCKETS = 513;
// Compute a 32-bit hash value from an sm_target structure. The hash
// values are used inside the ExSMTaskList class, to break the global
// collection of tasks into a set of hash buckets.
uint32_t hash(const sm_target_t &t, uint32_t numBuckets)
{
// We can return early if the number of buckets is 1
if (numBuckets == 1)
return 0;
const uint32_t R = 31;
int64_t result = t.node;
result = (result * R) + t.pid;
result = (result * R) + t.id;
result = (result * R) + t.tag;
return (uint32_t) (result % numBuckets);
}
ExSMTaskList::ExSMTaskList()
: buckets_(NULL),
numBuckets_(EXSM_DEFAULT_NUM_BUCKETS),
numTasks_(0),
numInserts_(0),
numCollisions_(0)
{
char *e = getenv("EXSM_NUM_BUCKETS");
if (e && e[0])
{
int temp = atoi(e);
if (temp > 0)
numBuckets_ = (uint32_t) temp;
}
buckets_ = new ExSMTask *[numBuckets_];
memset(buckets_, 0, sizeof(ExSMTask *) * numBuckets_);
EXSM_TRACE(EXSM_TRACE_INIT,
"TASK LIST CTOR %p buckets %u", this, numBuckets_);
int rc = pthread_mutex_init(&taskListMutex_, NULL);
exsm_assert_rc(rc, "pthread_mutex_init");
}
ExSMTaskList::~ExSMTaskList()
{
delete [] buckets_;
EXSM_TRACE(EXSM_TRACE_INIT,
"TASK LIST DTOR %p inserts %ld collisions %ld",
this, numInserts_, numCollisions_);
int rc = pthread_mutex_destroy(&taskListMutex_);
exsm_assert_rc(rc, "pthread_mutex_destroy");
}
void ExSMTaskList::lock()
{
int rc = pthread_mutex_lock(&taskListMutex_);
exsm_assert_rc(rc, "pthread_mutex_lock");
}
void ExSMTaskList::unlock()
{
int rc = pthread_mutex_unlock(&taskListMutex_);
exsm_assert_rc(rc, "pthread_mutex_unlock");
}
void ExSMTaskList::addTask(ExSMTask *t)
{
exsm_assert(t, "addTask called with NULL task");
lock();
uint32_t hashval = hash(t->getReceiver(), numBuckets_);
ExSMTask *&head = buckets_[hashval];
if (head != NULL)
numCollisions_++;
t->hashBucketNext_ = head;
head = t;
numTasks_++;
numInserts_++;
unlock();
}
void ExSMTaskList::removeTask(ExSMTask *t)
{
exsm_assert(t, "removeTask called with NULL task");
lock();
uint32_t hashval = hash(t->getReceiver(), numBuckets_);
ExSMTask *&head = buckets_[hashval];
bool found = false;
ExSMTask *previous = NULL;
ExSMTask *current = head;
while (current)
{
if (t == current)
{
if (previous)
previous->hashBucketNext_ = current->hashBucketNext_;
else
head = current->hashBucketNext_;
found = true;
numTasks_--;
break;
}
previous = current;
current = current->hashBucketNext_;
}
unlock();
exsm_assert(found, "removeTask failed to find the task");
}
ExSMTask *ExSMTaskList::findTask(const sm_target_t &target,
bool doLock,
bool doTrace)
{
if (doLock)
lock();
uint32_t hashval = hash(target, numBuckets_);
ExSMTask *&head = buckets_[hashval];
ExSMTask *result = NULL;
ExSMTask *current = head;
while (current)
{
const sm_target_t &receiver = current->getReceiver();
if (doTrace)
EXSM_TRACE(EXSM_TRACE_RDR_THR|EXSM_TRACE_WAIT,
"FINDTASK "
"%d:%d:%" PRId64 ":%d:0x%c %d:%d:%" PRId64 ":%d:0x%c",
(int) target.node, (int) target.pid, target.id,
(int) ExSMTag_GetTagWithoutQualifier(target.tag),
(char) ExSMTag_GetQualifierDisplay(target.tag),
(int) receiver.node, (int) receiver.pid, receiver.id,
(int) ExSMTag_GetTagWithoutQualifier(receiver.tag),
(char) ExSMTag_GetQualifierDisplay(receiver.tag));
if (ExSM_TargetsEqual(receiver, target))
{
result = current;
break;
}
current = current->hashBucketNext_;
}
if (doLock)
unlock();
return result;
}