167 lines
6.9 KiB
C
167 lines
6.9 KiB
C
|
/*******************************************************************************
|
||
|
Copyright (c) 2015-2019 NVIDIA Corporation
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
of this software and associated documentation files (the "Software"), to
|
||
|
deal in the Software without restriction, including without limitation the
|
||
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||
|
sell copies of the Software, and to permit persons to whom the Software is
|
||
|
furnished to do so, subject to the following conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be
|
||
|
included in all copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
*******************************************************************************/
|
||
|
|
||
|
#ifndef __UVM_THREAD_CONTEXT_H__
|
||
|
#define __UVM_THREAD_CONTEXT_H__
|
||
|
|
||
|
#include "uvm_forward_decl.h"
|
||
|
#include "uvm_lock.h"
|
||
|
#include "uvm_common.h"
|
||
|
#include "uvm_linux.h"
|
||
|
|
||
|
#define UVM_THREAD_CONTEXT_TABLE_SIZE 64
|
||
|
|
||
|
// Used to track lock correctness and store information about locks held by each
|
||
|
// thread.
|
||
|
struct uvm_thread_context_lock_struct
|
||
|
{
|
||
|
// Opt-out of lock tracking if >0
|
||
|
NvU32 skip_lock_tracking;
|
||
|
|
||
|
// Bitmap of acquired lock orders
|
||
|
DECLARE_BITMAP(acquired_lock_orders, UVM_LOCK_ORDER_COUNT);
|
||
|
|
||
|
// Bitmap of exclusively acquired lock orders
|
||
|
DECLARE_BITMAP(exclusive_acquired_lock_orders, UVM_LOCK_ORDER_COUNT);
|
||
|
|
||
|
// Bitmap of lock orders acquired out of order (via trylock)
|
||
|
DECLARE_BITMAP(out_of_order_acquired_lock_orders, UVM_LOCK_ORDER_COUNT);
|
||
|
|
||
|
// Array of pointers to acquired locks. Indexed by lock order, so the
|
||
|
// array size is UVM_LOCK_ORDER_COUNT
|
||
|
//
|
||
|
// The value at a given index is undefined if the corresponding bit is not
|
||
|
// set in acquired_locked_orders.
|
||
|
void **acquired;
|
||
|
};
|
||
|
|
||
|
// UVM thread contexts provide thread local storage for all logical threads
|
||
|
// executing in the UVM driver. Both user and interrupt contexts are supported.
|
||
|
struct uvm_thread_context_struct
|
||
|
{
|
||
|
// Pointer to the thread (task) associated with the context
|
||
|
//
|
||
|
// This field is ignored in interrupt paths
|
||
|
struct task_struct *task;
|
||
|
|
||
|
// This context is present at the given array index if array_index is less
|
||
|
// than UVM_THREAD_CONTEXT_ARRAY_SIZE; otherwise is in the tree.
|
||
|
//
|
||
|
// This field is ignored in interrupt paths
|
||
|
NvU32 array_index;
|
||
|
|
||
|
// Pointer to enclosing node (if any) in red-black tree
|
||
|
//
|
||
|
// This field is ignored in interrupt paths
|
||
|
struct rb_node node;
|
||
|
};
|
||
|
|
||
|
bool uvm_thread_context_wrapper_is_used(void);
|
||
|
|
||
|
// A thread context wrapper augments a thread context with additional
|
||
|
// information useful for debugging, profiling, etc. Since the extra information
|
||
|
// can take up considerable space, it is only allocated if
|
||
|
// uvm_thread_context_wrapper_is_used() returns true.
|
||
|
struct uvm_thread_context_wrapper_struct
|
||
|
{
|
||
|
uvm_thread_context_t context;
|
||
|
|
||
|
uvm_thread_context_lock_t context_lock;
|
||
|
};
|
||
|
|
||
|
bool uvm_thread_context_global_initialized(void);
|
||
|
void uvm_thread_context_global_init(void);
|
||
|
void uvm_thread_context_global_exit(void);
|
||
|
|
||
|
// Retrieve the current thread context. Asserts if it does not exist.
|
||
|
uvm_thread_context_t *uvm_thread_context(void);
|
||
|
|
||
|
// Returns true if the current thread context is present: it has been added but
|
||
|
// not removed, or we are in a interrupt path.
|
||
|
bool uvm_thread_context_present(void);
|
||
|
|
||
|
// Set the current thread context to be thread_context. Returns false if there
|
||
|
// is a different thread context already associated with the current task i.e.
|
||
|
// the insertion did not happen. This scenario arises when re-entering the UVM
|
||
|
// module, because the first entry point already associated the thread with a
|
||
|
// different thread context.
|
||
|
//
|
||
|
// Do not invoke this function in a interrupt path.
|
||
|
bool uvm_thread_context_add(uvm_thread_context_t *thread_context);
|
||
|
|
||
|
// Reset the current thread context, which should be thread_context.
|
||
|
//
|
||
|
// The current thread context is passed, even if it is guaranteed to match
|
||
|
// uvm_thread_context(), to avoid the lookup overhead.
|
||
|
//
|
||
|
// Do not invoke this function in a interrupt path.
|
||
|
void uvm_thread_context_remove(uvm_thread_context_t *thread_context);
|
||
|
|
||
|
// Add or remove thread contexts at the given global thread context table
|
||
|
// index. Used only in testing.
|
||
|
//
|
||
|
// Thread contexts inserted using uvm_thread_context_add_at cannot be retrieved
|
||
|
// using uvm_thread_context()
|
||
|
bool uvm_thread_context_add_at(uvm_thread_context_t *op_context, size_t table_index);
|
||
|
void uvm_thread_context_remove_at(uvm_thread_context_t *op_context, size_t table_index);
|
||
|
|
||
|
// Save the state of the current thread context to the given thread context, and
|
||
|
// then clear the state of the current thread context.
|
||
|
//
|
||
|
// Used only in testing: for example, we may want to ensure that a test starts
|
||
|
// with no locks held in the current thread context, so we save its state at the
|
||
|
// beginning of the test, and restore the state at the end.
|
||
|
//
|
||
|
// This function breaks any expectations about what the current thread context
|
||
|
// should contain. For example, any IOCTL entry point into the UVM module
|
||
|
// results on a power management lock being acquired. Clearing the lock state
|
||
|
// in the current thread context will confuse code that assumes the lock is
|
||
|
// acquired at all times.
|
||
|
void uvm_thread_context_save(uvm_thread_context_t *dst);
|
||
|
|
||
|
// Restore the state of the current thread context out of the given (backup)
|
||
|
// thread context.
|
||
|
void uvm_thread_context_restore(uvm_thread_context_t *src);
|
||
|
|
||
|
// Get the current thread lock context. Returns NULL if there is no thread lock
|
||
|
// context (we are in release mode, or an internal allocation failed).
|
||
|
uvm_thread_context_lock_t *uvm_thread_context_lock_get(void);
|
||
|
|
||
|
// Disable lock tracking in the current thread lock context
|
||
|
// Lock tracking is enabled by default, but can be disabled by using this
|
||
|
// function.
|
||
|
// The disable lock tracking calls are refcounted so to enable tracking back all
|
||
|
// of the disable calls have to be paired with an enable call.
|
||
|
//
|
||
|
// This is needed in some tests that need to violate lock ordering, e.g. one of
|
||
|
// the push tests acquires the push sema multiple times.
|
||
|
void uvm_thread_context_lock_disable_tracking(void);
|
||
|
|
||
|
// Enable back lock tracking in the current thread lock context. Should be
|
||
|
// paired with a previous uvm_thread_lock_context_disable_lock_tracking() call.
|
||
|
// The lock tracking is enabled back only when all previous disable calls have
|
||
|
// been paired with an enable call.
|
||
|
void uvm_thread_context_lock_enable_tracking(void);
|
||
|
|
||
|
#endif // __UVM_THREAD_CONTEXT_H__
|