blob: d3a44e2ffa725fd565be60be9880bc2c3060986e [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
37Kernel API
38
39Access to the genlock API can either be via the in-kernel API or via an
40optional character device (/dev/genlock). The character device is primarily
41to be used for legacy resource sharing APIs that cannot be easily changed.
42New resource sharing APIs from this point should implement a scheme specific
43wrapper for locking.
44
45To create or attach to an existing lock, a process or kernel driver must first
46create a handle. Each handle is linked to a single lock at any time. An entityi
47may have multiple handles, each associated with a different lock. Once a handle
48has been created, the owner may create a new lock or attach an existing lock
49that has been exported from a different handle.
50
51Once the handle has a lock attached, the owning process may attempt to lock the
52buffer for read or write. Write locks are exclusive, meaning that only one
53process may acquire it at any given time. Read locks are shared, meaning that
54multiple readers can hold the lock at the same time. Attempts to acquire a read
55lock with a writer active or a write lock with one or more readers or writers
56active will typically cause the process to block until the lock is acquired.
57When the lock is released, all waiting processes will be woken up. Ownership
58of the lock is reference counted, meaning that any one owner can "lock"
59multiple times. The lock will only be released from the owner when all the
60references to the lock are released via unlock.
61
62The owner of a write lock may atomically convert the lock into a read lock
63(which will wake up other processes waiting for a read lock) without first
64releasing the lock. The owner would simply issue a new request for a read lock.
65However, the owner of a read lock cannot convert it into a write lock in the
66same manner. To switch from a read lock to a write lock, the owner must
67release the lock and then try to reacquire it.
68
69These are the in-kernel API calls that drivers can use to create and
70manipulate handles and locks. Handles can either be created and managed
71completely inside of kernel space, or shared from user space via a file
72descriptor.
73
74* struct genlock_handle *genlock_get_handle(void)
75Create a new handle.
76
77* struct genlock_handle * genlock_get_handle_fd(int fd)
78Given a valid file descriptor, return the handle associated with that
79descriptor.
80
81* void genlock_put_handle(struct genlock_handle *)
82Release a handle.
83
84* struct genlock * genlock_create_lock(struct genlock_handle *)
85Create a new lock and attach it to the handle.
86
87* struct genlock * genlock_attach_lock(struct genlock_handle *handle, int fd)
88Given a valid file descriptor, get the lock associated with it and attach it to
89the handle.
90
91* void genlock_release_lock(struct genlock_handle *)
92Release a lock attached to a handle.
93
94* int genlock_lock(struct genlock_handle *, int op, int flags, u32 timeout)
95Lock or unlock the lock attached to the handle. A zero timeout value will
96be treated just like if the GENOCK_NOBLOCK flag is passed; if the lock
97can be acquired without blocking then do so otherwise return -EAGAIN.
98Function returns -ETIMEDOUT if the timeout expired or 0 if the lock was
99acquired.
100
101* int genlock_wait(struct genloc_handle *, u32 timeout)
102Wait for a lock held by the handle to go to the unlocked state. A non-zero
103timeout value must be passed. Returns -ETIMEDOUT if the timeout expired or
1040 if the lock is in an unlocked state.
105
106Character Device
107
108Opening an instance to the /dev/genlock character device will automatically
109create a new handle. All ioctl functions with the exception of NEW and
110RELEASE use the following parameter structure:
111
112struct genlock_lock {
113 int fd; /* Returned by EXPORT, used by ATTACH */
114 int op; /* Used by LOCK */
115 int flags; /* used by LOCK */
116 u32 timeout; /* Used by LOCK and WAIT */
117}
118
119*GENLOCK_IOC_NEW
120Create a new lock and attaches it to the handle. Returns -EINVAL if the handle
121already has a lock attached (use GENLOCK_IOC_RELEASE to remove it). Returns
122-ENOMEM if the memory for the lock can not be allocated. No data is passed
123from the user for this ioctl.
124
125*GENLOCK_IOC_EXPORT
126Export the currently attached lock to a file descriptor. The file descriptor
127is returned in genlock_lock.fd.
128
129*GENLOCK_IOC_ATTACH
130Attach an exported lock file descriptor to the current handle. Return -EINVAL
131if the handle already has a lock attached (use GENLOCK_IOC_RELEASE to remove
132it). Pass the file descriptor in genlock_lock.fd.
133
134*GENLOCK_IOC_LOCK
135Lock or unlock the attached lock. Pass the desired operation in
136genlock_lock.op:
137 * GENLOCK_WRLOCK - write lock
138 * GENLOCK_RDLOCK - read lock
139 * GENLOCK_UNLOCK - unlock an existing lock
140
141Pass flags in genlock_lock.flags:
142 * GENLOCK_NOBLOCK - Do not block if the lock is already taken
143
144Pass a timeout value in milliseconds in genlock_lock.timeout.
145genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
146Returns -EINVAL if no lock is attached, -EAGAIN if the lock is taken and
147NOBLOCK is specified or if the timeout value is zero, -ETIMEDOUT if the timeout
148expires or 0 if the lock was successful.
149
150* GENLOCK_IOC_WAIT
151Wait for the lock attached to the handle to be released (i.e. goes to unlock).
152This is mainly used for a thread that needs to wait for a peer to release a
153lock on the same shared handle. A non-zero timeout value in milliseconds is
154passed in genlock_lock.timeout. Returns 0 when the lock has been released,
155-EINVAL if a zero timeout is passed, or -ETIMEDOUT if the timeout expires.
156
157* GENLOCK_IOC_RELEASE
158Use this to release an existing lock. This is useful if you wish to attach a
159different lock to the same handle. You do not need to call this under normal
160circumstances; when the handle is closed the reference to the lock is released.
161No data is passed from the user for this ioctl.