/** * \file * Monitor locking functions * * Author: * Dick Porter (dick@ximian.com) * * (C) 2003 Ximian, Inc */ #ifndef _MONO_METADATA_MONITOR_H_ #define _MONO_METADATA_MONITOR_H_ #include #include #include #include G_BEGIN_DECLS #define OWNER_MASK 0x0000ffff #define ENTRY_COUNT_MASK 0xffff0000 #define ENTRY_COUNT_WAITERS 0x80000000 #define ENTRY_COUNT_ZERO 0x7fff0000 #define ENTRY_COUNT_SHIFT 16 struct _MonoThreadsSync { /* * The entry count field can be negative, which would mean that the entry_sem is * signaled and nobody is waiting to acquire it. This can happen when the thread * that was waiting is either interrupted or timeouts, and the owner releases * the lock before the forementioned thread updates the entry count. * * The 0 entry_count value is encoded as ENTRY_COUNT_ZERO, positive numbers being * greater than it and negative numbers smaller than it. */ guint32 status; /* entry_count (16) | owner_id (16) */ guint32 nest; #ifdef HAVE_MOVING_COLLECTOR gint32 hash_code; #endif GSList *wait_list; void *data; MonoCoopSem *entry_sem; }; /* * Lock word format: * * The least significant bit stores whether a hash for the object is computed * which is stored either in the lock word or in the MonoThreadsSync structure * that the lock word points to. * * The second bit stores whether the lock word is inflated, containing an * address to the MonoThreadsSync structure. * * If both bits are 0, either the lock word is free (entire lock word is 0) * or it is a thin/flat lock. * * 32-bit * LOCK_WORD_FLAT: [owner:22 | nest:8 | status:2] * LOCK_WORD_THIN_HASH: [hash:30 | status:2] * LOCK_WORD_INFLATED: [sync:30 | status:2] * LOCK_WORD_FAT_HASH: [sync:30 | status:2] * * 64-bit * LOCK_WORD_FLAT: [unused:22 | owner:32 | nest:8 | status:2] * LOCK_WORD_THIN_HASH: [hash:62 | status:2] * LOCK_WORD_INFLATED: [sync:62 | status:2] * LOCK_WORD_FAT_HASH: [sync:62 | status:2] * * In order to save processing time and to have one additional value, the nest * count starts from 0 for the lock word (just valid thread ID in the lock word * means that the thread holds the lock once, although nest is 0). * FIXME Have the same convention on inflated locks */ typedef union { #if SIZEOF_REGISTER == 8 guint64 lock_word; #elif SIZEOF_REGISTER == 4 guint32 lock_word; #endif MonoThreadsSync *sync; } LockWord; enum { LOCK_WORD_FLAT = 0, LOCK_WORD_HAS_HASH = 1, LOCK_WORD_INFLATED = 2, LOCK_WORD_STATUS_BITS = 2, LOCK_WORD_NEST_BITS = 8, LOCK_WORD_STATUS_MASK = (1 << LOCK_WORD_STATUS_BITS) - 1, LOCK_WORD_NEST_MASK = ((1 << LOCK_WORD_NEST_BITS) - 1) << LOCK_WORD_STATUS_BITS, LOCK_WORD_HASH_SHIFT = LOCK_WORD_STATUS_BITS, LOCK_WORD_NEST_SHIFT = LOCK_WORD_STATUS_BITS, LOCK_WORD_OWNER_SHIFT = LOCK_WORD_STATUS_BITS + LOCK_WORD_NEST_BITS }; MONO_API void mono_locks_dump (gboolean include_untaken); void mono_monitor_init (void); void mono_monitor_cleanup (void); MonoBoolean mono_monitor_enter_internal (MonoObject *obj); void mono_monitor_enter_v4_internal (MonoObject *obj, MonoBoolean *lock_taken); guint32 mono_monitor_enter_fast (MonoObject *obj); guint32 mono_monitor_enter_v4_fast (MonoObject *obj, MonoBoolean *lock_taken); guint32 mono_monitor_get_object_monitor_gchandle (MonoObject *object); void mono_monitor_threads_sync_members_offset (int *status_offset, int *nest_offset); #define MONO_THREADS_SYNC_MEMBER_OFFSET(o) ((o)>>8) #define MONO_THREADS_SYNC_MEMBER_SIZE(o) ((o)&0xff) extern MonoBoolean ves_icall_System_Threading_Monitor_Monitor_test_owner(MonoObject *obj); extern MonoBoolean ves_icall_System_Threading_Monitor_Monitor_test_synchronised(MonoObject *obj); extern void ves_icall_System_Threading_Monitor_Monitor_pulse(MonoObject *obj); extern void ves_icall_System_Threading_Monitor_Monitor_pulse_all(MonoObject *obj); extern MonoBoolean ves_icall_System_Threading_Monitor_Monitor_wait(MonoObject *obj, guint32 ms); extern void ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, MonoBoolean *lockTaken); G_END_DECLS #endif /* _MONO_METADATA_MONITOR_H_ */