Android的hwc可以通过ioctl,把buffer data信息送入fb driver,由fb控制acquireFence和retireFence,以达到buffer的producer和consumer互相同步的机制,但是假如我们的hwc没有现成的ioctl可以用,又没有办法改到driver的code,我们还有一个选择:hwc可以打开/dev/sw_sync设备,通过一系列的ioctl来监控和控制fence.
代码下载地址: https://android.googlesource.com/kernel/exynos.git
文章中用到的code:
exynos/include/linux/sync.h
exynos/drivers/base/sync.c
exynos/include/linux/sw_sync.h
exynos/drivers/base/sw_sync.c
在切入正文之前,我们先来了解下sync_timeline和sync_fence中出现的kref成员.在Android fb driver中的fence机制一文中,由于篇幅所限,没有对kref做过多的解释,在这一篇中我们来了解下kref的实现和工作原理.
关于kref
sync_timeline和sync_fence中都有一个struct kref kref的成员,这东西是干什么用的呢?
sync_pt中有直接指向sync_timeline和sync_fence的指针,当sync_pt通过这些指针对sync_timeline或sync_fence做一些操作的时候,如果不能保证指向sync_time和sync_fence的指针仍然有效,我们就有大麻烦了.
kref作为一个引用计数器可以我们帮助管理sync_timeline和sync_fence的生命周期,每当一个新的指针指向sync_time或者sync_fence时,通过kref_get增加计数;当指针不再需要的时候,通过kref_put减小计数;当kref引用为0时,自动调用对应struct的清理函数并释放资源.
那么kref是如何实现呢?其实非常简单,全部code都在单独的一个.h之中:include/linux/kref.h
struct kref {
atomic_t refcount;
};
kref只有一个原子类型的refcount成员.所有对于refcount的操作都是原子的,不需要加锁.
static inline void kref_init(struct kref *kref)
{
atomic_set(&kref->refcount, 1);
}
kref_init初始化refcount的值为1.
static inline void kref_get(struct kref *kref)
{
WARN_ON(!atomic_read(&kref->refcount));
atomic_inc(&kref->refcount);
}
kref_get增加refcount的计数.
static inline int kref_sub(struct kref *kref, unsigned int count,
void (*release)(struct kref *kref))
{
WARN_ON(release == NULL);
if (atomic_sub_and_test((int) count, &kref->refcount)) {
release(kref);
return 1;
}
return 0;
}
kref_sub减小count个refcount的计数,如果recount归零,则调用传进来的release函数指针.
static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
{
return kref_sub(kref, 1, release);
}
kref_put是count为1的kref_sub特例.
我们来看下kref在sync_time,sync_pt之间是如何运用的.
struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
int size, const char *name)
{
struct sync_timeline *obj;
obj = kzalloc(size, GFP_KERNEL);
...
kref_init(&obj->kref);
...
return obj;
}
sync_timeline_create的时候,对sync_timeline的kref成员做了初始化,kref->refcount == 1;
static void sync_timeline_free(struct kref *kref)
{
struct sync_timeline *obj =
container_of(kref, struct sync_timeline, kref);
unsigned long flags;
if (obj->ops->release_obj)
obj->ops->