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

📄 ref.c

📁 linux进程间高级通信的一个模块 是一个很不错的东西.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	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. */#include <linux/config.h>#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;     int         fusion_id;     int         refs;} LocalRef;typedef struct {     FusionLink  link;     FusionRef  *ref;} Inheritor;struct __Fusion_FusionRef {     FusionLink         link;     struct semaphore   lock;     int                id;     int                pid;     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;     wait_queue_head_t  wait;};/******************************************************************************/static int  lookup_ref (FusionDev *dev, bool locked, int id, FusionRef **ret_ref);static int  lock_ref   (FusionDev *dev, bool locked, int id, FusionRef **ret_ref);static void unlock_ref (FusionRef *ref);static int  add_local       (FusionRef *ref, int fusion_id, int add);static void clear_local     (FusionDev *dev, FusionRef *ref, int fusion_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 intrefs_read_proc(char *buf, char **start, off_t offset,               int len, int *eof, void *private){     FusionLink *l;     FusionDev  *dev     = private;     int         written = 0;     if (down_interruptible (&dev->ref.lock))          return -EINTR;     fusion_list_foreach (l, dev->ref.list) {          FusionRef *ref = (FusionRef*) l;          if (ref->locked)               written += sprintf(buf+written, "(%5d) 0x%08x %2d %2d (locked by %d)\n",                                  ref->pid, ref->id, ref->global, ref->local,                                  ref->locked);          else               written += sprintf(buf+written, "(%5d) 0x%08x %2d %2d\n",                                  ref->pid, ref->id, ref->global, ref->local);          if (written < offset) {               offset -= written;               written = 0;          }          if (written >= len)               break;     }     up (&dev->ref.lock);     *start = buf + offset;     written -= offset;     if (written > len) {          *eof = 0;          return len;     }     *eof = 1;     return(written<0) ? 0 : written;}intfusion_ref_init (FusionDev *dev){     init_MUTEX (&dev->ref.lock);     create_proc_read_entry("refs", 0, dev->proc_dir,                            refs_read_proc, dev);     return 0;}voidfusion_ref_deinit (FusionDev *dev){     FusionLink *l;     down (&dev->ref.lock);     remove_proc_entry ("refs", dev->proc_dir);     l = dev->ref.list;     while (l) {          FusionLink *next = l->next;          FusionRef  *ref  = (FusionRef *) l;          free_all_local (ref);          kfree (ref);          l = next;     }     up (&dev->ref.lock);}/******************************************************************************/intfusion_ref_new (FusionDev *dev, int *id){     FusionRef *ref;     ref = kmalloc (sizeof(FusionRef), GFP_KERNEL);     if (!ref)          return -ENOMEM;     memset (ref, 0, sizeof(FusionRef));     if (down_interruptible (&dev->ref.lock)) {          kfree (ref);          return -EINTR;     }     ref->id   = dev->ref.ids++;     ref->pid  = current->pid;     init_MUTEX (&ref->lock);     init_waitqueue_head (&ref->wait);     fusion_list_prepend (&dev->ref.list, &ref->link);     up (&dev->ref.lock);     *id = ref->id;     return 0;}intfusion_ref_up (FusionDev *dev, int id, int fusion_id){     int        ret;     FusionRef *ref;     ret = lookup_ref (dev, false, id, &ref);     if (ret)          return ret;     if (down_interruptible (&ref->lock)) {          up (&dev->ref.lock);          return -EINTR;     }     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:     up (&dev->ref.lock);     unlock_ref (ref);     return ret;}intfusion_ref_down (FusionDev *dev, int id, int fusion_id){     int        ret;     FusionRef *ref;     ret = lookup_ref (dev, false, id, &ref);     if (ret)          return ret;     if (down_interruptible (&ref->lock)) {          up (&dev->ref.lock);          return -EINTR;     }     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:     up (&dev->ref.lock);     unlock_ref (ref);     return ret;}intfusion_ref_zero_lock (FusionDev *dev, int id, int fusion_id){     int        ret;     FusionRef *ref;     while (true) {          ret = lock_ref (dev, false, id, &ref);          if (ret)               return ret;          if (ref->watched) {               unlock_ref (ref);               return -EACCES;          }          if (ref->locked) {               unlock_ref (ref);               return ref->locked == fusion_id ? -EIO : -EAGAIN;          }          if (ref->global || ref->local) {               fusion_sleep_on (&ref->wait, &ref->lock, 0);               if (signal_pending(current))                    return -EINTR;          }          else               break;     }     ref->locked = fusion_id;     unlock_ref (ref);     return 0;}intfusion_ref_zero_trylock (FusionDev *dev, int id, int fusion_id){     int        ret;     FusionRef *ref;     ret = lock_ref (dev, false, id, &ref);     if (ret)          return ret;     if (ref->locked) {          unlock_ref (ref);          return ref->locked == fusion_id ? -EIO : -EAGAIN;     }     if (ref->global || ref->local)          ret = -ETOOMANYREFS;     else          ref->locked = fusion_id;     unlock_ref (ref);     return ret;}intfusion_ref_unlock (FusionDev *dev, int id, int fusion_id){     int        ret;     FusionRef *ref;     ret = lock_ref (dev, false, id, &ref);     if (ret)          return ret;     if (ref->locked != fusion_id) {          unlock_ref (ref);          return -EIO;     }     ref->locked = 0;     unlock_ref (ref);     return 0;}intfusion_ref_stat (FusionDev *dev, int id, int *refs){     int        ret;     FusionRef *ref;     ret = lock_ref (dev, false, id, &ref);     if (ret)          return ret;     *refs = ref->global + ref->local;     unlock_ref (ref);

⌨️ 快捷键说明

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