[Mono-list] mono, porting to non glibc systems, and pthread mutex implementations...

Jeffrey Stedfast fejj@ximian.com
12 Feb 2002 23:18:07 -0500


--=-4U/rJEmVv+DoQ5FXGDhy
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

This weekend I began porting the mono interpreter to SPARC systems
although lupus@ximian.com apparently had the same idea and beat me to
the punch ;-)

Since Paolo didn't have access to a sparc, Miguel has asked me to test
the code and to finish porting if necessary. This also means porting
other code to SunOS/Solaris.

Unfortunately, SunOS 5.8 seems to not support the
PTHREAD_MUTEX_RECURSIVE attribute, nor does it seem to support
pthread_mutexattr_settype(). Reading my manpages on my Linux system also
show these as unsupported/non-portable (there was no
PTHREAD_MUTEX_RECUSIVE but there was a PTHREAD_MUTEX_RECURSIVE_NP and
there wasn't a pthread_mutexattr_settype() either) but a quick read in
pthread.h shows that these are enabled for UNIX98 systems.

To solve this problem, I have written a direct wrapper around
pthread_mutex_*() and pthread_mutexattr_*() functions that implement
recursive mutex locking for systems that don't support this natively
(see attached files).

Do begin using my wrapper, simply:

sed -e "s/pthread_mutex/mono_mutex/g" -e "s/PTHREAD_MUTEX/MONO_MUTEX"

(well, for the most part that will work unless we later decide to set
process-sharing attributes or other attributes other than the mutex
types - in which case you'll have to s/PTHREAD/MONO_THREAD/g)

I've also noticed that a function named pthread_mutex_timedlock() is
being used. What does this function do? I can't find it in any
documentation I have on pthreads...
I've noticed that configure.in will AC_WARN() if it's not there and that
there is a #define specifying whether or not it is available but I did
not see checks around the code that uses pthread_mutex_timedlock().
Perhaps I missed something...

Anyways, if someone would like to enlighten me as to what it does,
perhaps I can hack mono_mutex_t to support that operation...

Also: where should these files go? any preferences or shall I dump them
in mono/metadata/?

Jeff

-- 
Jeffrey Stedfast
Evolution Hacker - Ximian, Inc.
fejj@ximian.com  - www.ximian.com

--=-4U/rJEmVv+DoQ5FXGDhy
Content-Disposition: attachment; filename=mono-mutex.h
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c-header; charset=ISO-8859-1

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 *  Authors: Jeffrey Stedfast <fejj@ximian.com>
 *
 *  Copyright 2002 Ximain, Inc. (www.ximian.com)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
 *
 */


#ifndef __MONO_MUTEX_H__
#define __MONO_MUTEX_H__

#ifdef __cplusplus
extern "C" {
#pragma }
#endif /* __cplusplus */

#include <pthread.h>

#ifdef USE_MONO_MUTEX

#define MONO_THREAD_NONE ((pthread_t)~0)

/* mutex types... */
enum {
	MONO_MUTEX_NORMAL,
	MONO_MUTEX_RECURSIVE,
	MONO_MUTEX_ERRORCHECK =3D MONO_MUTEX_NORMAL,
	MONO_MUTEX_DEFAULT =3D MONO_MUTEX_NORMAL
};

/* mutex protocol attributes... */
enum {
	MONO_THREAD_PRIO_NONE,
	MONO_THREAD_PRIO_INHERIT,
	MONO_THREAD_PRIO_PROTECT,
};

/* mutex process sharing attributes... */
enum {
	MONO_THREAD_PROCESS_PRIVATE,
	MONO_THREAD_PROCESS_SHARED
};

typedef struct _mono_mutexattr_t {
	int type     : 1;
	int shared   : 1;
	int protocol : 2;
	int priority : 28;
} mono_mutexattr_t;

typedef struct _mono_mutex_t {
	int type;
	pthread_t owner;
	short waiters;
	short depth;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
} mono_mutex_t;

/* static initializers */
#define MONO_MUTEX_INITIALIZER { 0, MONO_THREAD_NONE, 0, 0, PTHREAD_MUTEX_I=
NITIALIZER, 0 }
#define MONO_RECURSIVE_MUTEX_INITIALIZER { 0, MONO_THREAD_NONE, 0, 0, PTHRE=
AD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER }


int mono_mutexattr_init (mono_mutexattr_t *attr);
int mono_mutexattr_settype (mono_mutexattr_t *attr, int type);
int mono_mutexattr_gettype (mono_mutexattr_t *attr, int *type);
int mono_mutexattr_setpshared (mono_mutexattr_t *attr, int pshared);
int mono_mutexattr_getpshared (mono_mutexattr_t *attr, int *pshared);
int mono_mutexattr_setprotocol (mono_mutexattr_t *attr, int protocol);
int mono_mutexattr_getprotocol (mono_mutexattr_t *attr, int *protocol);
int mono_mutexattr_setprioceiling (mono_mutexattr_t *attr, int prioceiling)=
;
int mono_mutexattr_getprioceiling (mono_mutexattr_t *attr, int *prioceiling=
);
int mono_mutexattr_destroy (mono_mutexattr_t *attr);


int mono_mutex_init (mono_mutex_t *mutex, const mono_mutexattr_t *attr);
int mono_mutex_lock (mono_mutex_t *mutex);
int mono_mutex_trylock (mono_mutex_t *mutex);
int mono_mutex_unlock (mono_mutex_t *mutex);
int mono_mutex_destroy (mono_mutex_t *mutex);

#else /* system is equipped with a fully-functional pthread mutex library *=
/

#define MONO_MUTEX_NORMAL             PTHREAD_MUTEX_NORMAL
#define MONO_MUTEX_RECURSIVE          PTHREAD_MUTEX_RECURSIVE
#define MONO_MUTEX_ERRORCHECK         PTHREAD_MUTEX_NORMAL
#define MONO_MUTEX_DEFAULT            PTHREAD_MUTEX_NORMAL

#define MONO_THREAD_PRIO_NONE         PTHREAD_PRIO_NONE
#define MONO_THREAD_PRIO_INHERIT      PTHREAD_PRIO_INHERIT
#define MONO_THREAD_PRIO_PROTECT      PTHREAD_PRIO_PROTECT

#define MONO_THREAD_PROCESS_PRIVATE   PTHREAD_PROCESS_PRIVATE
#define MONO_THREAD_PROCESS_SHARED    PTHREAD_PROCESS_SHARED

typedef pthread_mutex_t mono_mutex_t;
typedef pthread_mutexattr_t mono_mutexattr_t;

#define MONO_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#define MONO_RECURSIVE_MUTEX_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZE=
R

#define mono_mutexattr_init(attr) pthread_mutexattr_init (attr)
#define mono_mutexattr_settype(attr,type) pthread_mutexattr_settype (attr, =
type)
#define mono_mutexattr_gettype(attr,type) pthread_mutexattr_gettype (attr, =
type)
#define mono_mutexattr_setpshared(attr,pshared) pthread_mutexattr_setpshare=
d (attr, pshared)
#define mono_mutexattr_getpshared(attr,pshared) pthread_mutexattr_getpshare=
d (attr, pshared)
#define mono_mutexattr_setprotocol(attr,protocol) pthread_mutexattr_setprot=
ocol (attr, protocol)
#define mono_mutexattr_getprotocol(attr,protocol) pthread_mutexattr_getprot=
ocol (attr, protocol)
#define mono_mutexattr_setprioceiling(attr,prioceiling) pthread_mutexattr_s=
etprioceiling (attr, prioceiling)
#define mono_mutexattr_getprioceiling(attr,prioceiling) pthread_mutexattr_g=
etprioceiling (attr, prioceiling)

#define mono_mutex_init(mutex,attr) pthread_mutex_init (mutex, attr)
#define mono_mutex_lock(mutex) pthread_mutex_lock (mutex)
#define mono_mutex_trylock(mutex) pthread_mutex_trylock (mutex)
#define mono_mutex_unlock(mutex) pthread_mutex_unlock (mutex)
#define mono_mutex_destroy(mutex) pthread_mutex_destroy (mutex)

#endif /* USE_MONO_MUTEX */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __MONO_MUTEX_H__ */

--=-4U/rJEmVv+DoQ5FXGDhy
Content-Disposition: attachment; filename=mono-mutex.c
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c; charset=ISO-8859-1

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 *  Authors: Jeffrey Stedfast <fejj@ximian.com>
 *
 *  Copyright 2002 Ximain, Inc. (www.ximian.com)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
 *
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "mono-mutex.h"

#ifdef USE_MONO_MUTEX

int
mono_mutexattr_init (mono_mutexattr_t *attr)
{
	memset (attr, 0, sizeof (mono_mutexattr_t));
	return 0;
}

int
mono_mutexattr_settype (mono_mutexattr_t *attr, int type)
{
	attr->type =3D type;
	return 0;
}

int
mono_mutexattr_gettype (mono_mutexattr_t *attr, int *type)
{
	*type =3D attr->type;
	return 0;
}

int
mono_mutexattr_setpshared (mono_mutexattr_t *attr, int pshared)
{
	attr->pshared =3D pshared;
	return 0;
}

int
mono_mutexattr_getpshared (mono_mutexattr_t *attr, int *pshared)
{
	*pshared =3D attr->pshared;
	return 0;
}

int
mono_mutexattr_setprotocol (mono_mutexattr_t *attr, int protocol)
{
	attr->protocol =3D protocol;
	return 0;
}

int
mono_mutexattr_getprotocol (mono_mutexattr_t *attr, int *protocol)
{
	*protocol =3D attr->protocol;
	return 0;
}

int
mono_mutexattr_setprioceiling (mono_mutexattr_t *attr, int prioceiling)
{
	attr->prioceiling =3D prioceiling;
	return 0;
}

int
mono_mutexattr_getprioceiling (mono_mutexattr_t *attr, int *prioceiling)
{
	*prioceiling =3D attr->prioceiling;
	return 0;
}

int
mono_mutexattr_destroy (mono_mutexattr_t *attr)
{
	g_free (attr);
	return 0;
}


int
mono_mutex_init (mono_mutex_t *mutex, const mono_mutexattr_t *attr)
{
	mutex->waiters =3D 0;
	mutex->depth =3D 0;
	mutex->owner =3D MONO_THREAD_NONE;
=09
	if (!attr || attr->type =3D=3D MONO_MUTEX_NORMAL) {
		mutex->type =3D MONO_MUTEX_NORMAL;
		pthread_mutex_init (&mutex->mutex, NULL);
	} else {
		mutex->type =3D MONO_MUTEX_RECURSIVE;
		pthread_mutex_init (&mutex->mutex, NULL);
		pthread_cond_init (&mutex->cond, NULL);
	}
=09
	return 0;
}

int
mono_mutex_lock (mono_mutex_t *mutex)
{
	pthread_t id;
=09
	switch (mutex->type) {
	case MONO_MUTEX_NORMAL:
		return pthread_mutex_lock (&mutex->mutex);
	case MONO_MUTEX_RECURSIVE:
		id =3D pthread_self ();
		if (pthread_mutex_lock (&mutex->mutex) =3D=3D -1)
			return -1;
		while (1) {
			if (mutex->owner =3D=3D MONO_THREAD_NONE) {
				mutex->owner =3D id;
				mutex->depth =3D 1;
				break;
			} else if (id =3D=3D mutex->owner) {
				mutex->depth++;
				break;
			} else {
				mutex->waiters++;
				if (pthread_cond_wait (&mutex->cond, &mutex->mutex) =3D=3D -1)
					return -1;
				mutex->waiters--;
			}
		}
	=09
		return pthread_mutex_unlock (&mutex->mutex);
	}
=09
	errno =3D EINVAL;
=09
	return -1;
}

int
mono_mutex_trylock (mono_mutex_t *mutex)
{
	switch (mutex->type) {
	case MONO_MUTEX_NORMAL:
		return pthread_mutex_trylock (&mutex->mutex);
	case MONO_MUTEX_RECURSIVE:
		if (pthread_mutex_lock (&mutex->mutex) =3D=3D -1)
			return -1;
	=09
		if (mutex->id !=3D MONO_THREAD_NONE && mutex->id !=3D pthread_self ()) {
			pthread_mutex_unlock (&mutex->mutex);
			errno =3D EBUSY;
			return -1;
		}
	=09
		while (1) {
			if (mutex->owner =3D=3D MONO_THREAD_NONE) {
				mutex->owner =3D id;
				mutex->depth =3D 1;
				break;
			} else if (id =3D=3D mutex->owner) {
				mutex->depth++;
				break;
			} else {
				mutex->waiters++;
				if (pthread_cond_wait (&mutex->cond, &mutex->mutex) =3D=3D -1)
					return -1;
				mutex->waiters--;
			}
		}
	=09
		return pthread_mutex_unlock (&mutex->mutex);
	}
}

int
mono_mutex_unlock (mono_mutex_t *mutex)
{
	switch (mutex->type) {
	case MONO_MUTEX_NORMAL:
		return pthread_mutex_unlock (&mutex->mutex);
	case MONO_MUTEX_RECURSIVE:
		if (pthread_mutex_lock (&mutex->mutex) =3D=3D -1)
			return -1;
	=09
		g_assert (mutex->owner =3D=3D pthread_self ());
	=09
		mutex->depth--;
		if (mutex->depth =3D=3D 0) {
			mutex->owner =3D MONO_THREAD_NONE;
			if (mutex->waiters > 0)
				pthread_cond_signal (&mutex->cond);
		}
	=09
		return pthread_mutex_unlock (&mutex->mutex);
	}
=09
	errno =3D EINVAL;
=09
	return -1;
}

int
mono_mutex_destroy (mono_mutex_t *mutex)
{
	int ret =3D 0;
=09
	switch (mutex->type) {
	case MONO_MUTEX_NORMAL:
		ret =3D pthread_mutex_destroy (&mutex->mutex);
		g_free (mutex);
		break;
	case MONO_MUTEX_RECURSIVE:
		ret =3D pthread_mutex_destroy (&mutex->mutex);
		ret =3D pthread_cond_destroy (&mutex->cond);
		g_free (mutex);
	}
=09
	return ret;
}

#endif /* USE_MONO_MUTEX */

--=-4U/rJEmVv+DoQ5FXGDhy--