<div dir="ltr"><br><div class="gmail_extra">Hi,<br></div><div class="gmail_extra"><br></div><div class="gmail_extra">Just minor comments<br></div><div class="gmail_extra"><div class="gmail_quote"><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+Usage<br>
+-----<br>
+<br>
+Three different ways to acquire locks within the same w/w class. Common<br>
+definitions for methods #1 and #2:<br>
+<br>
+static DEFINE_WW_CLASS(ww_class);<br>
+<br>
+struct obj {<br>
+       struct ww_mutex lock;<br>
+       /* obj data */<br>
+};<br>
+<br>
+struct obj_entry {<br>
+       struct list_head *list;<br>
+       struct obj *obj;<br>
+};<br>
+<br>
+Method 1, using a list in execbuf->buffers that's not allowed to be reordered.<br>
+This is useful if a list of required objects is already tracked somewhere.<br>
+Furthermore the lock helper can use propagate the -EALREADY return code back to<br>
+the caller as a signal that an object is twice on the list. This is useful if<br>
+the list is constructed from userspace input and the ABI requires userspace to<br>
+not have duplicate entries (e.g. for a gpu commandbuffer submission ioctl).<br>
+<br>
+int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)<br>
+{<br>
+       struct obj *res_obj = NULL;<br>
+       struct obj_entry *contended_entry = NULL;<br>
+       struct obj_entry *entry;<br>
+<br>
+       ww_acquire_init(ctx, &ww_class);<br>
+<br>
+retry:<br>
+       list_for_each_entry (list, entry) {<br>
+               if (entry == res_obj) {<br></blockquote><div><br></div><div>if (entry->obj == res_obj) {<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+                       res_obj = NULL;<br>
+                       continue;<br>
+               }<br>
+               ret = ww_mutex_lock(&entry->obj->lock, ctx);<br>
+               if (ret < 0) {<br>
+                       contended_obj = entry;<br></blockquote><div><br></div><div>contended_entry = entry;<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+                       goto err;<br>
+               }<br>
+       }<br>
+<br>
+       ww_acquire_done(ctx);<br>
+       return 0;<br>
+<br>
+err:<br>
+       list_for_each_entry_continue_reverse (list, contended_entry, entry)<br></blockquote><div><br></div><div>list_for_each_entry_continue_reverse(entry, list, list)?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+               ww_mutex_unlock(&entry->obj->lock);<br>
+<br>
+       if (res_obj)<br>
+               ww_mutex_unlock(&res_obj->lock);<br>
+<br>
+       if (ret == -EDEADLK) {<br>
+               /* we lost out in a seqno race, lock and retry.. */<br>
+               ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);<br>
+               res_obj = contended_entry->obj;<br>
+               goto retry;<br>
+       }<br>
+       ww_acquire_fini(ctx);<br>
+<br>
+       return ret;<br>
+}<br>
+<br>
+Method 2, using a list in execbuf->buffers that can be reordered. Same semantics<br>
+of duplicate entry detection using -EALREADY as method 1 above. But the<br>
+list-reordering allows for a bit more idiomatic code.<br>
+<br>
+int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)<br>
+{<br>
+       struct obj_entry *entry, *entry2;<br>
+<br>
+       ww_acquire_init(ctx, &ww_class);<br>
+<br>
+       list_for_each_entry (list, entry) {<br>
+               ret = ww_mutex_lock(&entry->obj->lock, ctx);<br>
+               if (ret < 0) {<br>
+                       entry2 = entry;<br>
+<br>
+                       list_for_each_entry_continue_reverse (list, entry2)<br></blockquote><div><br></div><div>list_for_each_entry_continue_reverse(entry, list, list)?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+                               ww_mutex_unlock(&entry->obj->lock);<br>
+<br>
+                       if (ret != -EDEADLK) {<br>
+                               ww_acquire_fini(ctx);<br>
+                               return ret;<br>
+                       }<br>
+<br>
+                       /* we lost out in a seqno race, lock and retry.. */<br>
+                       ww_mutex_lock_slow(&entry->obj->lock, ctx);<br></blockquote><div><br></div><div>shouldn't the wounded task acquire slowpath lock to the above dead locked entry like this, ww_mutex_lock_slow(&entry2->obj->lock, ctx)?<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+                       /*<br>
+                        * Move buf to head of the list, this will point<br>
+                        * buf->next to the first unlocked entry,<br>
+                        * restarting the for loop.<br>
+                        */<br>
+                       list_del(&entry->list);<br>
+                       list_add(&entry->list, list);<br>
+               }<br>
+       }<br>
+<br>
+       ww_acquire_done(ctx);<br>
+       return 0;<br>
+}<br>
+<br>
+Unlocking works the same way for both methods #1 and #2:<br>
+<br>
+void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)<br>
+{<br>
+       struct obj_entry *entry;<br>
+<br>
+       list_for_each_entry (list, entry)<br>
+               ww_mutex_unlock(&entry->obj->lock);<br>
+<br>
+       ww_acquire_fini(ctx);<br>
+}<br>
+<br>
<br>
_______________________________________________<br>
dri-devel mailing list<br>
<a href="mailto:dri-devel@lists.freedesktop.org">dri-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/dri-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/dri-devel</a><br>
</blockquote></div><br></div></div>