1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.navigation.internal 18 19 import kotlin.experimental.ExperimentalNativeApi 20 import kotlin.native.ref.createCleaner 21 import kotlinx.cinterop.Arena 22 import kotlinx.cinterop.ExperimentalForeignApi 23 import kotlinx.cinterop.alloc 24 import kotlinx.cinterop.ptr 25 import platform.posix.pthread_mutex_destroy 26 import platform.posix.pthread_mutex_init 27 import platform.posix.pthread_mutex_lock 28 import platform.posix.pthread_mutex_t 29 import platform.posix.pthread_mutex_unlock 30 import platform.posix.pthread_mutexattr_destroy 31 import platform.posix.pthread_mutexattr_init 32 import platform.posix.pthread_mutexattr_settype 33 import platform.posix.pthread_mutexattr_t 34 35 /** 36 * Wrapper for platform.posix.PTHREAD_MUTEX_RECURSIVE which is represented as kotlin.Int on darwin 37 * platforms and kotlin.UInt on linuxX64 See: // https://youtrack.jetbrains.com/issue/KT-41509 38 */ 39 internal expect val PTHREAD_MUTEX_RECURSIVE: Int 40 41 internal actual class SynchronizedObject actual constructor() { 42 43 private val resource = Resource() 44 45 @Suppress("unused") // The returned Cleaner must be assigned to a property 46 @OptIn(ExperimentalNativeApi::class) 47 private val cleaner = createCleaner(resource, Resource::dispose) 48 locknull49 fun lock() { 50 resource.lock() 51 } 52 unlocknull53 fun unlock() { 54 resource.unlock() 55 } 56 57 @OptIn(ExperimentalForeignApi::class) 58 private class Resource { 59 private val arena: Arena = Arena() 60 private val attr: pthread_mutexattr_t = arena.alloc() 61 private val mutex: pthread_mutex_t = arena.alloc() 62 63 init { 64 pthread_mutexattr_init(attr.ptr) 65 pthread_mutexattr_settype(attr.ptr, PTHREAD_MUTEX_RECURSIVE) 66 pthread_mutex_init(mutex.ptr, attr.ptr) 67 } 68 locknull69 fun lock(): Int = pthread_mutex_lock(mutex.ptr) 70 71 fun unlock(): Int = pthread_mutex_unlock(mutex.ptr) 72 73 fun dispose() { 74 pthread_mutex_destroy(mutex.ptr) 75 pthread_mutexattr_destroy(attr.ptr) 76 arena.clear() 77 } 78 } 79 } 80 synchronizedImplnull81internal actual inline fun <T> synchronizedImpl( 82 lock: SynchronizedObject, 83 crossinline action: () -> T 84 ): T { 85 lock.lock() 86 return try { 87 action() 88 } finally { 89 lock.unlock() 90 } 91 } 92