1 // Copyright 2016 The Fuchsia Authors 2 // 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file or at 5 // https://opensource.org/licenses/MIT 6 7 #pragma once 8 9 #include <lib/user_copy/user_ptr.h> 10 #include <zircon/types.h> 11 #include <fbl/mutex.h> 12 #include <kernel/lockdep.h> 13 #include <object/futex_node.h> 14 15 // FutexContext is a class that encapsulates support for futex operations. 16 // FutexContext uses a hash table keyed on the futex address (a pointer to integer in userspace) 17 // to contain all active futexes. 18 // A futex is considered active if there is one or more threads blocked on the futex. 19 // After no threads are left blocked on a futex it is removed from the hash table. 20 // The value in the futex hash table is the FutexNode object associated with the head 21 // of the list of threads blocked on the futex. 22 // To avoid memory allocation at futex operation time, a FutexNode is embedded in each 23 // ThreadDispatcher object. 24 // When the thread at the head of the futex's blocked thread list is resumed, 25 // The FutexNode for the new head of the blocked thread list is set as the hash table value 26 // for the futex. 27 class FutexContext { 28 public: 29 FutexContext(); 30 ~FutexContext(); 31 32 enum class OwnerAction { 33 RELEASE, 34 ASSIGN_WOKEN, 35 }; 36 37 // FutexWait first verifies that the integer pointed to by |value_ptr| 38 // still equals |current_value|. If the test fails, FutexWait returns ZX_ERR_BAD_STATE. 39 // Otherwise it will block the current thread until the |slack|-adjusted |deadline| passes, 40 // or until the thread is woken by a FutexWake or FutexRequeue operation 41 // on the same |value_ptr| futex. 42 zx_status_t FutexWait(user_in_ptr<const zx_futex_t> value_ptr, zx_futex_t current_value, 43 zx_handle_t new_futex_owner, zx_time_t deadline, TimerSlack slack); 44 45 // FutexWake will wake up to |wake_count| number of threads blocked on the |value_ptr| futex. 46 // 47 // If owner_action is set to RELEASE, then the futex's owner will be set to nullptr in the 48 // process. If the owner_action is set to ASSIGN_WOKEN, then the wake_count *must* be 1, and 49 // the futex's owner will be set to the thread which was woken during the operation, or nullptr 50 // if no thread was woken. 51 zx_status_t FutexWake(user_in_ptr<const zx_futex_t> value_ptr, uint32_t wake_count, 52 OwnerAction owner_action); 53 54 // FutexWait first verifies that the integer pointed to by |wake_ptr| 55 // still equals |current_value|. If the test fails, FutexWait returns ZX_ERR_BAD_STATE. 56 // Otherwise it will wake up to |wake_count| number of threads blocked on the |wake_ptr| futex. 57 // If any other threads remain blocked on on the |wake_ptr| futex, up to |requeue_count| 58 // of them will then be requeued to the tail of the list of threads 59 // blocked on the |requeue_ptr| futex. 60 // 61 // If owner_action is set to RELEASE, then the futex's owner will be set to nullptr in the 62 // process. If the owner_action is set to ASSIGN_WOKEN, then the wake_count *must* be 1, and 63 // the futex's owner will be set to the thread which was woken during the operation, or nullptr 64 // if no thread was woken. 65 zx_status_t FutexRequeue(user_in_ptr<const zx_futex_t> wake_ptr, 66 uint32_t wake_count, 67 zx_futex_t current_value, 68 OwnerAction owner_action, 69 user_in_ptr<const zx_futex_t> requeue_ptr, 70 uint32_t requeue_count, 71 zx_handle_t new_requeue_owner); 72 73 // Get the KOID of the current owner of the specified futex, if any, or ZX_KOID_INVALID if there 74 // is no known owner. 75 zx_status_t FutexGetOwner(user_in_ptr<const zx_futex_t> wake_ptr, 76 user_out_ptr<zx_koid_t> koid); 77 78 private: 79 FutexContext(const FutexContext&) = delete; 80 FutexContext& operator=(const FutexContext&) = delete; 81 82 void QueueNodesLocked(FutexNode* head) TA_REQ(lock_); 83 84 bool UnqueueNodeLocked(FutexNode* node) TA_REQ(lock_); 85 86 // protects futex_table_ 87 DECLARE_MUTEX(FutexContext) lock_; 88 89 // Hash table for futexes in this context. 90 // Key is futex address, value is the FutexNode for the head of futex's blocked thread list. 91 FutexNode::HashTable futex_table_ TA_GUARDED(lock_); 92 }; 93