blob: cd8261467748a8ab6887345b54ab34f9c2ae46df [file] [log] [blame]
Jordan Crouse29f66af2011-11-17 13:39:20 -07001Introduction
2
3'genlock' is an in-kernel API and optional userspace interface for a generic
4cross-process locking mechanism. The API is designed for situations where
5multiple user space processes and/or kernel drivers need to coordinate access
6to a shared resource, such as a graphics buffer. The API was designed with
7graphics buffers in mind, but is sufficiently generic to allow it to be
8independently used with different types of resources. The chief advantage
9of genlock over other cross-process locking mechanisms is that the resources
10can be accessed by both userspace and kernel drivers which allows resources
11to be locked or unlocked by asynchronous events in the kernel without the
12intervention of user space.
13
14As an example, consider a graphics buffer that is shared between a rendering
15application and a compositing window manager. The application renders into a
16buffer. That buffer is reused by the compositing window manager as a texture.
17To avoid corruption, access to the buffer needs to be restricted so that one
18is not drawing on the surface while the other is reading. Locks can be
19explicitly added between the rendering stages in the processes, but explicit
20locks require that the application wait for rendering and purposely release the
21lock. An implicit release triggered by an asynchronous event from the GPU
22kernel driver, however, will let execution continue without requiring the
23intercession of user space.
24
25SW Goals
26
27The genlock API implements exclusive write locks and shared read locks meaning
28that there can only be one writer at a time, but multiple readers. Processes
29that are unable to acquire a lock can be optionally blocked until the resource
30becomes available.
31
32Locks are shared between processes. Each process will have its own private
33instance for a lock known as a handle. Handles can be shared between user
34space and kernel space to allow a kernel driver to unlock or lock a buffer
35on behalf of a user process.
36
Jeff Boody6d9076f2012-04-26 11:12:44 -060037Locks within a process using a single genlock handle follow the same rules for
38exclusive write locks with multiple readers. Genlock cannot provide deadlock
39protection because the same handle can be used simultaneously by a producer and
40consumer. In practice in the event that the client creates a deadlock an error
41will still be generated when the timeout expires.
42
Jordan Crouse29f66af2011-11-17 13:39:20 -070043Kernel API
44
45Access to the genlock API can either be via the in-kernel API or via an
46optional character device (/dev/genlock). The character device is primarily
47to be used for legacy resource sharing APIs that cannot be easily changed.
48New resource sharing APIs from this point should implement a scheme specific
49wrapper for locking.
50
51To create or attach to an existing lock, a process or kernel driver must first
52create a handle. Each handle is linked to a single lock at any time. An entityi
53may have multiple handles, each associated with a different lock. Once a handle
54has been created, the owner may create a new lock or attach an existing lock
55that has been exported from a different handle.
56
57Once the handle has a lock attached, the owning process may attempt to lock the
58buffer for read or write. Write locks are exclusive, meaning that only one
59process may acquire it at any given time. Read locks are shared, meaning that
60multiple readers can hold the lock at the same time. Attempts to acquire a read
61lock with a writer active or a write lock with one or more readers or writers
62active will typically cause the process to block until the lock is acquired.
63When the lock is released, all waiting processes will be woken up. Ownership
64of the lock is reference counted, meaning that any one owner can "lock"
65multiple times. The lock will only be released from the owner when all the
66references to the lock are released via unlock.
67
68The owner of a write lock may atomically convert the lock into a read lock
69(which will wake up other processes waiting for a read lock) without first
70releasing the lock. The owner would simply issue a new request for a read lock.
71However, the owner of a read lock cannot convert it into a write lock in the
72same manner. To switch from a read lock to a write lock, the owner must
73release the lock and then try to reacquire it.
74
75These are the in-kernel API calls that drivers can use to create and
76manipulate handles and locks. Handles can either be created and managed
77completely inside of kernel space, or shared from user space via a file
78descriptor.
79
80* struct genlock_handle *genlock_get_handle(void)
81Create a new handle.
82
83* struct genlock_handle * genlock_get_handle_fd(int fd)
84Given a valid file descriptor, return the handle associated with that
85descriptor.
86
87* void genlock_put_handle(struct genlock_handle *)
88Release a handle.
89
90* struct genlock * genlock_create_lock(struct genlock_handle *)
Jordan Crouse4df70a22012-01-25 14:40:51 -070091Create a new lock and attach it to the handle. Once a lock is attached to a
92handle it stays attached until the handle is destroyed.
Jordan Crouse29f66af2011-11-17 13:39:20 -070093
94* struct genlock * genlock_attach_lock(struct genlock_handle *handle, int fd)
95Given a valid file descriptor, get the lock associated with it and attach it to
96the handle.
97
Jordan Crouse29f66af2011-11-17 13:39:20 -070098* int genlock_lock(struct genlock_handle *, int op, int flags, u32 timeout)
99Lock or unlock the lock attached to the handle. A zero timeout value will
100be treated just like if the GENOCK_NOBLOCK flag is passed; if the lock
101can be acquired without blocking then do so otherwise return -EAGAIN.
102Function returns -ETIMEDOUT if the timeout expired or 0 if the lock was
103acquired.
104
105* int genlock_wait(struct genloc_handle *, u32 timeout)
106Wait for a lock held by the handle to go to the unlocked state. A non-zero
107timeout value must be passed. Returns -ETIMEDOUT if the timeout expired or
1080 if the lock is in an unlocked state.
109
110Character Device
111
112Opening an instance to the /dev/genlock character device will automatically
113create a new handle. All ioctl functions with the exception of NEW and
114RELEASE use the following parameter structure:
115
116struct genlock_lock {
117 int fd; /* Returned by EXPORT, used by ATTACH */
118 int op; /* Used by LOCK */
119 int flags; /* used by LOCK */
120 u32 timeout; /* Used by LOCK and WAIT */
121}
122
123*GENLOCK_IOC_NEW
124Create a new lock and attaches it to the handle. Returns -EINVAL if the handle
125already has a lock attached (use GENLOCK_IOC_RELEASE to remove it). Returns
126-ENOMEM if the memory for the lock can not be allocated. No data is passed
127from the user for this ioctl.
128
129*GENLOCK_IOC_EXPORT
130Export the currently attached lock to a file descriptor. The file descriptor
131is returned in genlock_lock.fd.
132
133*GENLOCK_IOC_ATTACH
134Attach an exported lock file descriptor to the current handle. Return -EINVAL
135if the handle already has a lock attached (use GENLOCK_IOC_RELEASE to remove
136it). Pass the file descriptor in genlock_lock.fd.
137
138*GENLOCK_IOC_LOCK
139Lock or unlock the attached lock. Pass the desired operation in
140genlock_lock.op:
141 * GENLOCK_WRLOCK - write lock
142 * GENLOCK_RDLOCK - read lock
143 * GENLOCK_UNLOCK - unlock an existing lock
144
145Pass flags in genlock_lock.flags:
Jeff Boody6d9076f2012-04-26 11:12:44 -0600146 * GENLOCK_NOBLOCK - Do not block if the lock is already taken
147 * GENLOCK_WRITE_TO_READ - Convert a write lock that the handle owns to a read
148 lock. For instance graphics may hold a write lock
149 while rendering the back buffer then when swapping
150 convert the lock to a read lock to copy the front
151 buffer in the next frame for preserved buffers.
Jordan Crouse29f66af2011-11-17 13:39:20 -0700152
153Pass a timeout value in milliseconds in genlock_lock.timeout.
154genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
155Returns -EINVAL if no lock is attached, -EAGAIN if the lock is taken and
156NOBLOCK is specified or if the timeout value is zero, -ETIMEDOUT if the timeout
157expires or 0 if the lock was successful.
158
159* GENLOCK_IOC_WAIT
160Wait for the lock attached to the handle to be released (i.e. goes to unlock).
161This is mainly used for a thread that needs to wait for a peer to release a
162lock on the same shared handle. A non-zero timeout value in milliseconds is
163passed in genlock_lock.timeout. Returns 0 when the lock has been released,
164-EINVAL if a zero timeout is passed, or -ETIMEDOUT if the timeout expires.
165
166* GENLOCK_IOC_RELEASE
Jordan Crouse4df70a22012-01-25 14:40:51 -0700167This ioctl has been deprecated. Do not use.