<commit_before>package sync

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

// RWMutex provides locking functions, and an ability to detect and remove
// deadlocks.
type RWMutex struct {
	openLocks        map[int]lockInfo
	openLocksCounter int
	openLocksMutex   sync.Mutex

	callDepth   int
	maxLockTime time.Duration

	mu sync.RWMutex
}

// lockInfo contains information about when and how a lock call was made.
type lockInfo struct {
	// When the lock was called.
	lockTime time.Time

	// Call stack of the caller.
	callingFiles []string
	callingLines []int
}

// New takes a maxLockTime and returns a lock. The lock will never stay locked
// for more than maxLockTime, instead printing an error and unlocking after
// maxLockTime has passed.
func New(maxLockTime time.Duration, callDepth int) *RWMutex {
	rwm := &RWMutex{
		openLocks:   make(map[int]lockInfo),
		maxLockTime: maxLockTime,
		callDepth:   callDepth,
	}

	go rwm.threadedDeadlockFinder()

	return rwm
}

// threadedDeadlockFinder occasionally freezes the mutexes and scans all open mutexes,
// reporting any that have exceeded their time limit.
func (rwm *RWMutex) threadedDeadlockFinder() {
	for {
		rwm.openLocksMutex.Lock()
		for id, info := range rwm.openLocks {
			// Check if the lock has been held for longer than 'maxLockTime'.
			if time.Now().Sub(info.lockTime) > rwm.maxLockTime {
				fmt.Printf("A lock was held for too long, id '%v'. Call stack:\n", id)
				for i := 0; i <= rwm.callDepth; i++ {
					fmt.Printf("\tFile: '%v:%v'\n", info.callingFiles[i], info.callingLines[i])
				}
			}
		}
		rwm.openLocksMutex.Unlock()

		time.Sleep(rwm.maxLockTime)
	}
}

// safeLock is the generic function for doing safe locking. If the read flag is
// set, then a readlock will be used, otherwise a lock will be used.
func (rwm *RWMutex) safeLock(read bool) int {
	// Get the call stack.
	var li lockInfo
	li.lockTime = time.Now()
	li.callingFiles = make([]string, rwm.callDepth+1)
	li.callingLines = make([]int, rwm.callDepth+1)
	for i := 0; i <= rwm.callDepth; i++ {
		_, li.callingFiles[i], li.callingLines[i], _ = runtime.Caller(2 + i)
	}

	// Safely register that a lock has been triggered.
	rwm.openLocksMutex.Lock()
	counter := rwm.openLocksCounter
	rwm.openLocks[counter] = li
	rwm.openLocksCounter++
	rwm.openLocksMutex.Unlock()

	// Lock the mutex.
	if read {
		rwm.mu.RLock()
	} else {
		rwm.mu.Lock()
	}

	return counter
}<commit_msg>register a lock as locked after the lock has been obtained<commit_after>package sync

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

// RWMutex provides locking functions, and an ability to detect and remove
// deadlocks.
type RWMutex struct {
	openLocks        map[int]lockInfo
	openLocksCounter int
	openLocksMutex   sync.Mutex

	callDepth   int
	maxLockTime time.Duration

	mu sync.RWMutex
}

// lockInfo contains information about when and how a lock call was made.
type lockInfo struct {
	// When the lock was called.
	lockTime time.Time

	// Call stack of the caller.
	callingFiles []string
	callingLines []int
}

// New takes a maxLockTime and returns a lock. The lock will never stay locked
// for more than maxLockTime, instead printing an error and unlocking after
// maxLockTime has passed.
func New(maxLockTime time.Duration, callDepth int) *RWMutex {
	rwm := &RWMutex{
		openLocks:   make(map[int]lockInfo),
		maxLockTime: maxLockTime,
		callDepth:   callDepth,
	}

	go rwm.threadedDeadlockFinder()

	return rwm
}

// threadedDeadlockFinder occasionally freezes the mutexes and scans all open mutexes,
// reporting any that have exceeded their time limit.
func (rwm *RWMutex) threadedDeadlockFinder() {
	for {
		rwm.openLocksMutex.Lock()
		for id, info := range rwm.openLocks {
			// Check if the lock has been held for longer than 'maxLockTime'.
			if time.Now().Sub(info.lockTime) > rwm.maxLockTime {
				fmt.Printf("A lock was held for too long, id '%v'. Call stack:\n", id)
				for i := 0; i <= rwm.callDepth; i++ {
					fmt.Printf("\tFile: '%v:%v'\n", info.callingFiles[i], info.callingLines[i])
				}
			}
		}
		rwm.openLocksMutex.Unlock()

		time.Sleep(rwm.maxLockTime)
	}
}

// safeLock is the generic function for doing safe locking. If the read flag is
// set, then a readlock will be used, otherwise a lock will be used.
func (rwm *RWMutex) safeLock(read bool) int {
	// Get the call stack.
	var li lockInfo
	li.callingFiles = make([]string, rwm.callDepth+1)
	li.callingLines = make([]int, rwm.callDepth+1)
	for i := 0; i <= rwm.callDepth; i++ {
		_, li.callingFiles[i], li.callingLines[i], _ = runtime.Caller(2 + i)
	}

	// Lock the mutex.
	if read {
		rwm.mu.RLock()
	} else {
		rwm.mu.Lock()
	}

	// Safely register that a lock has been triggered.
	rwm.openLocksMutex.Lock()
	li.lockTime = time.Now()
	counter := rwm.openLocksCounter
	rwm.openLocks[counter] = li
	rwm.openLocksCounter++
	rwm.openLocksMutex.Unlock()

	return counter
}
{'fraction_non_alphanumeric': 0.11158974358974359, 'fraction_numerical': 0.0020512820512820513, 'mean_word_length': 3.5698219306466727, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3568932', 'n_tokens_mistral': 1773, 'n_tokens_neox': 1719, 'n_words': 532}