. , FreeBSD , . , .
, - . pthread_mutex_trylock, CPU, , . , , , EOWNERDEAD .
, :
#ifndef PTHREAD_MUTEX_ROBUST
#define TSRA__ALTERNATE
#define TSRA_MAX_MUTEXABANDON TSRA_MAX_MUTEX * 4
#endif
typedef struct mutex_lock_table_tag__ mutexlock_t;
struct mutex_lock_table_tag__
{
pthread_mutex_t *mutex;
tsra_daclbk audcallbk;
tsra_daclbk reicallbk;
int acbkstat;
int rcbkstat;
pthread_t owner;
#ifdef TSRA__OVERRIDE
tsra_clnup_t *cleanup;
#endif
};
pthread_rwlock_t tab_lock;
pthread_mutexattr_t mtx_attrib;
mutexlock_t *mutex_table;
int tabsizeentry;
int tabsizebyte;
int initialized = 0;
#ifdef TSRA__ALTERNATE
pthread_mutex_t *mutex_abandon[TSRA_MAX_MUTEXABANDON];
pthread_mutex_t mtx_abandon;
int mtx_abandon_count;
int mtx_abandon_init = 0;
#endif
pthread_mutex_t mtx_recover;
:
int tsra_mutex_recover(int lockid, pthread_t tid)
{
int result;
if (initialized == 0) return(EDOOFUS);
if (lockid < 0 || lockid >= tabsizeentry) return(EINVAL);
result = pthread_equal(tid, mutex_table[lockid].owner);
if (result != 0) return(0);
result = pthread_mutex_lock(&mtx_recover);
if (result != 0) return(result);
result = pthread_equal(tid, mutex_table[lockid].owner);
if (result != 0)
{
pthread_mutex_unlock(&mtx_recover);
return(0);
}
#ifdef TSRA__ALTERNATE
pthread_mutex_t *ptr;
if (mtx_abandon_count >= TSRA_MAX_MUTEXABANDON)
{
result = TSRA_PROGRAM_ABORT;
goto error_1;
}
result = pthread_rwlock_rdlock(&tab_lock);
if (result != 0) goto error_1;
if (mutex_table[lockid].acbkstat != 0)
{
result = mutex_table[lockid].audcallbk();
if (result != 0)
{
result = TSRA_PROGRAM_ABORT;
goto error_2;
}
}
ptr = malloc(sizeof(pthread_mutex_t));
if (ptr == NULL)
{
result = errno;
goto error_2;
}
result = pthread_mutex_init(ptr, &mtx_attrib);
if (result != 0) goto error_3;
mutex_abandon[mtx_abandon_count] = mutex_table[lockid].mutex;
mutex_abandon[mtx_abandon_count] = mutex_table[lockid].mutex;
mtx_abandon_count++;
mutex_table[lockid].mutex = ptr;
#else
result = pthread_mutex_trylock(mutex_table[lockid].mutex);
switch (result)
{
case 0:
pthread_unlock_mutex(mutex_table[lockid].mutex);
return(0);
break;
case EBUSY:
return(0);
break;
case EOWNERDEAD:
if (mutex_table[lockid].acbkstat != 0)
{
result = mutex_table[lockid].audcallbk();
if (result != 0)
{
if (mutex_table[lockid].rcbkstat != 0)
{
result = mutex_table[lockid].reicallbk();
if (result != 0)
{
result = TSRA_PROGRAM_ABORT;
goto error_2;
}
}
else
{
result = TSRA_PROGRAM_ABORT;
goto error_2;
}
}
}
else
{
result = TSRA_PROGRAM_ABORT;
goto error_2;
}
break;
case EDEADLK:
case ENOTRECOVERABLE:
abort();
break;
default:
abort();
break;
}
pthread_mutex_consistant(mutex_table[lockid].mutex);
pthread_mutex_unlock(mutex_table[lockid].mutex);
#endif
mutex_table[lockid].owner = pthread_self();
pthread_mutex_unlock(&mtx_recover);
return(0);
#ifdef TSRA__ALTERNATE
error_3:
free(ptr);
error_2:
pthread_rwlock_unlock(&tab_lock);
#else
error_2:
pthread_mutex_unlock(mutex_table[lockid].mutex);
#endif
error_1:
pthread_mutex_unlock(&mtx_recover);
return(result);
}
FreeBSD - , Linux, . , , .
, . , , , , , , . , , , , . , , . , , , . , , .
. . , , . , . , abort() .
, . , . , mutex pthread_mutex_lock pthread_mutex_trylock. , . , mutex, , , , .
, /, . , , , .