⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ref.c

📁 linux下的fusion程序,可以和directfb配合使用
💻 C
字号:
/* *	Fusion Kernel Module * *	(c) Copyright 2002-2003  Convergence GmbH * *      Written by Denis Oliver Kropp <dok@directfb.org> * * *	This program is free software; you can redistribute it and/or *	modify it under the terms of the GNU General Public License *	as published by the Free Software Foundation; either version *	2 of the License, or (at your option) any later version. */#ifdef HAVE_LINUX_CONFIG_H#include <linux/config.h>#endif#include <linux/types.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/sched.h>#include <linux/fusion.h>#include "fusiondev.h"#include "list.h"#include "call.h"#include "ref.h"typedef struct __Fusion_FusionRef FusionRef;typedef struct {     FusionLink     link;     FusionID       fusion_id;     int            refs;} LocalRef;typedef struct {     FusionLink     link;     FusionRef     *ref;} Inheritor;struct __Fusion_FusionRef {     FusionEntry    entry;     int            global;     int            local;     int            locked;    /* non-zero fusion id of lock owner */     bool           watched;   /* true if watch has been installed */     int            call_id;   /* id of call registered with a watch */     int            call_arg;  /* optional call parameter */     FusionRef     *inherited;     FusionLink    *inheritors;     FusionLink    *local_refs;};/**********************************************************************************************************************/static int  add_local       ( FusionRef *ref, FusionID fusion_id, int add );static void clear_local     ( FusionDev *dev, FusionRef *ref, FusionID fusion_id );static int  fork_local      ( FusionDev *dev, FusionRef *ref, FusionID fusion_id, FusionID from_id );static void free_all_local  ( FusionRef *ref );static int  propagate_local ( FusionDev *dev, FusionRef *ref, int diff );static void notify_ref      ( FusionDev *dev, FusionRef *ref );static int  add_inheritor   ( FusionRef *ref, FusionRef *from );static void remove_inheritor( FusionRef *ref, FusionRef *from );static void drop_inheritors ( FusionDev *dev, FusionRef *ref );/**********************************************************************************************************************/static voidfusion_ref_destruct( FusionEntry *entry,                     void        *ctx ){     FusionRef *ref = (FusionRef*) entry;     FusionDev *dev = (FusionDev*) ctx;     drop_inheritors( dev, ref );     if (ref->inherited)          remove_inheritor( ref, ref->inherited );     free_all_local( ref );}static intfusion_ref_print( FusionEntry *entry,                  void        *ctx,                  char        *buf ){     FusionRef *ref = (FusionRef*) entry;     if (ref->locked)          return sprintf( buf, "%2d %2d (locked by %d)\n", ref->global, ref->local, ref->locked );     return sprintf( buf, "%2d %2d\n", ref->global, ref->local );}FUSION_ENTRY_CLASS( FusionRef, ref, NULL,                    fusion_ref_destruct, fusion_ref_print );/**********************************************************************************************************************/intfusion_ref_init( FusionDev *dev ){     fusion_entries_init( &dev->ref, &ref_class, dev );     create_proc_read_entry( "refs", 0, dev->proc_dir, fusion_entries_read_proc, &dev->ref );     return 0;}voidfusion_ref_deinit( FusionDev *dev ){     remove_proc_entry( "refs", dev->proc_dir );     fusion_entries_deinit( &dev->ref );}/**********************************************************************************************************************/intfusion_ref_new( FusionDev *dev, int *ret_id ){     return fusion_entry_create( &dev->ref, ret_id, NULL );}intfusion_ref_up (FusionDev *dev, int id, FusionID fusion_id){     int        ret;     FusionRef *ref;     ret = fusion_ref_lock( &dev->ref, id, true, &ref );     if (ret)          return ret;     dev->stat.ref_up++;     if (ref->locked) {          ret = -EAGAIN;          goto out;     }     if (fusion_id) {          ret = add_local (ref, fusion_id, 1);          if (ret)               goto out;          ret = propagate_local( dev, ref, 1 );     }     else          ref->global++;out:     fusion_ref_unlock( ref );     up( &dev->ref.lock );     return ret;}intfusion_ref_down (FusionDev *dev, int id, FusionID fusion_id){     int        ret;     FusionRef *ref;     ret = fusion_ref_lock( &dev->ref, id, true, &ref );     if (ret)          return ret;     dev->stat.ref_down++;     if (ref->locked) {          ret = -EAGAIN;          goto out;     }     if (fusion_id) {          ret = -EIO;          if (!ref->local)               goto out;          ret = add_local (ref, fusion_id, -1);          if (ret)               goto out;          ret = propagate_local( dev, ref, -1 );     }     else {          if (!ref->global) {               ret = -EIO;               goto out;          }          ref->global--;          if (ref->local + ref->global == 0)               notify_ref (dev, ref);     }out:     fusion_ref_unlock( ref );     up( &dev->ref.lock );     return ret;}intfusion_ref_zero_lock (FusionDev *dev, int id, FusionID fusion_id){     int        ret;     FusionRef *ref;     ret = fusion_ref_lock( &dev->ref, id, false, &ref );     if (ret)          return ret;     while (true) {          if (ref->watched) {               fusion_ref_unlock( ref );               return -EACCES;          }          if (ref->locked) {               fusion_ref_unlock( ref );               return ref->locked == fusion_id ? -EIO : -EAGAIN;          }          if (ref->global || ref->local) {               ret = fusion_ref_wait( ref, NULL );               if (ret)                    return ret;          }          else               break;     }     ref->locked = fusion_id;     fusion_ref_unlock( ref );     return 0;}intfusion_ref_zero_trylock (FusionDev *dev, int id, FusionID fusion_id){     int        ret;     FusionRef *ref;     ret = fusion_ref_lock( &dev->ref, id, false, &ref );     if (ret)          return ret;     if (ref->locked) {          fusion_ref_unlock( ref );          return ref->locked == fusion_id ? -EIO : -EAGAIN;     }     if (ref->global || ref->local)          ret = -ETOOMANYREFS;     else          ref->locked = fusion_id;     fusion_ref_unlock( ref );     return ret;}intfusion_ref_zero_unlock (FusionDev *dev, int id, FusionID fusion_id){     int        ret;     FusionRef *ref;     ret = fusion_ref_lock( &dev->ref, id, false, &ref );     if (ret)          return ret;     if (ref->locked != fusion_id) {          fusion_ref_unlock( ref );          return -EIO;     }     ref->locked = 0;     fusion_ref_unlock( ref );     return 0;}intfusion_ref_stat (FusionDev *dev, int id, int *refs){     int        ret;     FusionRef *ref;     ret = fusion_ref_lock( &dev->ref, id, false, &ref );     if (ret)          return ret;     *refs = ref->global + ref->local;     fusion_ref_unlock( ref );     return 0;}intfusion_ref_watch (FusionDev      *dev,                  int             id,                  int             call_id,                  int             call_arg){     int        ret;     FusionRef *ref;     ret = fusion_ref_lock( &dev->ref, id, false, &ref );     if (ret)          return ret;     if (ref->entry.pid != current->pid) {          fusion_ref_unlock( ref );          return -EACCES;     }     if (ref->global + ref->local == 0) {          fusion_ref_unlock( ref );          return -EIO;     }     if (ref->watched) {          fusion_ref_unlock( ref );          return -EBUSY;     }     ref->watched  = true;     ref->call_id  = call_id;     ref->call_arg = call_arg;     fusion_ref_notify( ref, true );     fusion_ref_unlock( ref );     return 0;}intfusion_ref_inherit (FusionDev *dev,                    int        id,                    int        from_id){     int        ret;     FusionRef *ref;     FusionRef *from = NULL;     ret = fusion_ref_lock( &dev->ref, id, true, &ref );     if (ret)          return ret;     ret = -EBUSY;     if (ref->inherited)          goto out;     ret = -EINVAL;     fusion_list_foreach (from, dev->ref.list) {          if (from->entry.id == from_id) {               if (down_interruptible( &from->entry.lock )) {                    ret  = -EINTR;                    from = NULL;               }               break;          }     }     if (!from)          goto out;     ret = add_inheritor( ref, from );     if (ret)          goto out;     ret = propagate_local( dev, ref, from->local );     if (ret)          goto out;     ref->inherited = from;out:     if (from)          up( &from->entry.lock );     fusion_ref_unlock( ref );     up ( &dev->ref.lock );     return ret;}intfusion_ref_destroy (FusionDev *dev, int id){     return fusion_entry_destroy( &dev->ref, id );}voidfusion_ref_clear_all_local( FusionDev *dev, FusionID fusion_id ){     FusionRef *ref;     down( &dev->ref.lock );     fusion_list_foreach (ref, dev->ref.list)          clear_local( dev, ref, fusion_id );     up( &dev->ref.lock );}intfusion_ref_fork_all_local( FusionDev *dev, FusionID fusion_id, FusionID from_id ){     FusionRef *ref;     int        ret = 0;     down( &dev->ref.lock );     fusion_list_foreach (ref, dev->ref.list) {          ret = fork_local( dev, ref, fusion_id, from_id );          if (ret)               break;     }     up( &dev->ref.lock );     return ret;}/**********************************************************************************************************************/static intadd_local (FusionRef *ref, FusionID fusion_id, int add){     FusionLink *l;     LocalRef   *local;     fusion_list_foreach (l, ref->local_refs) {          local = (LocalRef *) l;          if (local->fusion_id == fusion_id) {               fusion_list_move_to_front( &ref->local_refs, l );               if (local->refs + add < 0)                    return -EIO;               local->refs += add;               return 0;          }     }     /* Can only create local node if value is positive. */     if (add <= 0)          return -EIO;     local = kmalloc (sizeof(LocalRef), GFP_KERNEL);     if (!local)          return -ENOMEM;     local->fusion_id = fusion_id;     local->refs      = add;     fusion_list_prepend (&ref->local_refs, &local->link);     return 0;}static voidclear_local (FusionDev *dev, FusionRef *ref, FusionID fusion_id){     FusionLink *l;     down (&ref->entry.lock);     if (ref->locked == fusion_id) {          ref->locked = 0;          wake_up_interruptible_all (&ref->entry.wait);     }     fusion_list_foreach (l, ref->local_refs) {          LocalRef *local = (LocalRef *) l;          if (local->fusion_id == fusion_id) {               if (local->refs)                    propagate_local( dev, ref, - local->refs );               fusion_list_remove( &ref->local_refs, l );               kfree (l);               break;          }     }     up (&ref->entry.lock);}static intfork_local (FusionDev *dev, FusionRef *ref, FusionID fusion_id, FusionID from_id){     FusionLink *l;     int         ret = 0;     down (&ref->entry.lock);     fusion_list_foreach (l, ref->local_refs) {          LocalRef *local = (LocalRef *) l;          if (local->fusion_id == from_id) {               if (local->refs) {#if 0                    LocalRef *new_local;                    new_local = kmalloc (sizeof(LocalRef), GFP_KERNEL);                    if (!new_local) {                         ret = -ENOMEM;                         break;                    }                    new_local->fusion_id = fusion_id;                    new_local->refs      = local->refs;                    fusion_list_prepend( &ref->local_refs, &new_local->link );                    propagate_local( dev, ref, local->refs );#else                    local->refs++;#endif               }               break;          }     }     up (&ref->entry.lock);     return ret;}static voidfree_all_local (FusionRef *ref){     FusionLink *l = ref->local_refs;     while (l) {          FusionLink *next = l->next;          kfree (l);          l = next;     }     ref->local_refs = NULL;}static voidnotify_ref (FusionDev *dev, FusionRef *ref){     if (ref->watched) {          FusionCallExecute execute;          execute.call_id  = ref->call_id;          execute.call_arg = ref->call_arg;          execute.call_ptr = NULL;          fusion_call_execute (dev, 0, &execute);     }     else          wake_up_interruptible_all (&ref->entry.wait);}static intpropagate_local( FusionDev *dev, FusionRef *ref, int diff ){     FusionLink *l;     /* Recurse into inheritors. */     fusion_list_foreach (l, ref->inheritors) {          FusionRef *inheritor = ((Inheritor*) l)->ref;          if (down_interruptible( &inheritor->entry.lock )) {               printk( KERN_ERR "fusion_ref: propagate_local() interrupted!\n" );               //return -EINTR;          }          propagate_local( dev, inheritor, diff );          up( &inheritor->entry.lock );     }     /* Apply difference. */     ref->local += diff;     /* Notify zero count. */     if (ref->local + ref->global == 0)          notify_ref( dev, ref );     return 0;}static intadd_inheritor(FusionRef *ref, FusionRef *from){     Inheritor *inheritor;     inheritor = kmalloc (sizeof(Inheritor), GFP_KERNEL);     if (!inheritor)          return -ENOMEM;     inheritor->ref = ref;     fusion_list_prepend( &from->inheritors, &inheritor->link );     return 0;}static voidremove_inheritor(FusionRef *ref, FusionRef *from){     FusionLink *l;     down( &from->entry.lock );     fusion_list_foreach (l, from->inheritors) {          Inheritor *inheritor = (Inheritor*) l;          if (inheritor->ref == ref) {               fusion_list_remove( &from->inheritors, &inheritor->link );               kfree( l );               break;          }     }     up( &from->entry.lock );}static voiddrop_inheritors( FusionDev *dev, FusionRef *ref ){     FusionLink *l = ref->inheritors;     while (l) {          FusionLink *next      = l->next;          FusionRef  *inheritor = ((Inheritor*) l)->ref;          if (down_interruptible( &inheritor->entry.lock )) {               printk( KERN_ERR "fusion_ref: drop_inheritors() interrupted!\n" );               //return;          }          propagate_local( dev, inheritor, - ref->local );          inheritor->inherited = NULL;          up( &inheritor->entry.lock );          kfree (l);          l = next;     }     ref->inheritors = NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -