📄 reactor.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 "call.h"#include "fusiondev.h"#include "fusionee.h"#include "list.h"#include "reactor.h"#include "shmpool.h"typedef struct { FusionLink link; int fusion_id; int *counts; /* number of attach calls */ int num_counts;} ReactorNode;typedef struct { int count; /* number of recipients */ int call_id; /* id of call to execute when count reaches zero */ int call_arg; /* optional parameter of user space */ void *call_ptr;} ReactorDispatch;typedef struct { FusionEntry entry; FusionLink *nodes; int dispatch_count; bool destroyed; int call_id; void *call_ptr;} FusionReactor;/******************************************************************************/static int fork_node ( FusionReactor *reactor, FusionID fusion_id, FusionID from_id );static void free_all_nodes( FusionReactor *reactor );/******************************************************************************/static inline ReactorNode *get_node (FusionReactor *reactor, FusionID fusion_id){ ReactorNode *node; fusion_list_foreach (node, reactor->nodes) { if (node->fusion_id == fusion_id) return node; } return NULL;}/******************************************************************************/static voidfusion_reactor_destruct( FusionEntry *entry, void *ctx ){ FusionReactor *reactor = (FusionReactor*) entry; free_all_nodes( reactor );}static intfusion_reactor_print( FusionEntry *entry, void *ctx, char *buf ){ int num = 0; FusionReactor *reactor = (FusionReactor*) entry; FusionLink *node = reactor->nodes; fusion_list_foreach (node, reactor->nodes) { num++; } return sprintf( buf, "%5dx dispatch, %d nodes%s\n", reactor->dispatch_count, num, reactor->destroyed ? " DESTROYED" : "" );}FUSION_ENTRY_CLASS( FusionReactor, reactor, NULL, fusion_reactor_destruct, fusion_reactor_print )/******************************************************************************/intfusion_reactor_init (FusionDev *dev){ fusion_entries_init( &dev->reactor, &reactor_class, dev ); create_proc_read_entry( "reactors", 0, dev->proc_dir, fusion_entries_read_proc, &dev->reactor ); return 0;}voidfusion_reactor_deinit (FusionDev *dev){ remove_proc_entry ("reactors", dev->proc_dir); fusion_entries_deinit( &dev->reactor );}/******************************************************************************/intfusion_reactor_new (FusionDev *dev, int *ret_id){ return fusion_entry_create( &dev->reactor, ret_id, NULL );}intfusion_reactor_attach (FusionDev *dev, int id, int channel, FusionID fusion_id){ int ret; ReactorNode *node; FusionReactor *reactor; if (channel < 0 || channel > 1023) return -EINVAL; ret = fusion_reactor_lock( &dev->reactor, id, false, &reactor ); if (ret) return ret; if (reactor->destroyed) { fusion_reactor_unlock( reactor ); return -EIDRM; } dev->stat.reactor_attach++; node = get_node (reactor, fusion_id); if (!node) { int ncount = channel + 4; node = kmalloc (sizeof(ReactorNode), GFP_KERNEL); if (!node) { fusion_reactor_unlock( reactor ); return -ENOMEM; } node->counts = kmalloc( sizeof(int) * ncount, GFP_KERNEL ); if (!node->counts) { kfree( node ); fusion_reactor_unlock( reactor ); return -ENOMEM; } node->num_counts = ncount; node->fusion_id = fusion_id; node->counts[channel] = 1; fusion_list_prepend (&reactor->nodes, &node->link); } else { if (node->num_counts <= channel) { int ncount = channel + 4; int *counts = kmalloc( sizeof(int) * ncount, GFP_KERNEL ); if (!counts) { fusion_reactor_unlock( reactor ); return -ENOMEM; } memcpy( counts, node->counts, sizeof(int) * node->num_counts ); memset( counts + node->num_counts, 0, sizeof(int) * (ncount - node->num_counts) ); node->counts = counts; node->num_counts = ncount; } node->counts[channel]++; } fusion_reactor_unlock( reactor ); return 0;}intfusion_reactor_detach (FusionDev *dev, int id, int channel, FusionID fusion_id){ int ret; ReactorNode *node; FusionReactor *reactor; if (channel < 0 || channel > 1023) return -EINVAL; ret = fusion_reactor_lock( &dev->reactor, id, true, &reactor ); if (ret) return ret; dev->stat.reactor_detach++; node = get_node (reactor, fusion_id); if (!node || node->num_counts <= channel) { fusion_reactor_unlock( reactor ); up( &dev->reactor.lock ); return -EIO; } if (! --node->counts[channel]) { int i; for (i=0; i<node->num_counts; i++) { if (node->counts[i]) break; } if (i == node->num_counts) { fusion_list_remove (&reactor->nodes, &node->link); kfree (node->counts); kfree (node); } } if (reactor->destroyed && !reactor->nodes) fusion_entry_destroy_locked( &dev->reactor, &reactor->entry ); else fusion_reactor_unlock( reactor ); up( &dev->reactor.lock ); return 0;}static voiddispatch_callback( FusionDev *dev, int id, void *ctx, int arg ){ FusionLink *l; FusionReactor *reactor = NULL; ReactorDispatch *dispatch = ctx; down (&dev->reactor.lock); fusion_list_foreach (l, dev->reactor.list) { reactor = (FusionReactor *) l; if (reactor->entry.id == id) { down (&reactor->entry.lock); if (! --dispatch->count) { FusionCallExecute execute; execute.call_id = dispatch->call_id; execute.call_arg = dispatch->call_arg; execute.call_ptr = dispatch->call_ptr; fusion_call_execute( dev, NULL, &execute ); kfree( dispatch ); } up (&reactor->entry.lock); break; } } if (!reactor) { if (! --dispatch->count) kfree( dispatch ); } up( &dev->reactor.lock );}intfusion_reactor_dispatch (FusionDev *dev, int id, int channel, Fusionee *fusionee, int msg_size, const void *msg_data){ int ret; FusionLink *l; FusionReactor *reactor; ReactorDispatch *dispatch = NULL; FusionID fusion_id = fusionee ? fusionee_id( fusionee ) : 0; if (channel < 0 || channel > 1023) return -EINVAL; ret = fusion_reactor_lock( &dev->reactor, id, false, &reactor ); if (ret) return ret; if (reactor->destroyed) { fusion_reactor_unlock( reactor ); return -EIDRM; } if (reactor->call_id) { void *ptr = *(void**)msg_data; dispatch = kmalloc (sizeof(ReactorDispatch), GFP_KERNEL); if (!dispatch) { fusion_reactor_unlock( reactor ); return -ENOMEM; } dispatch->count = 0; dispatch->call_id = reactor->call_id; dispatch->call_arg = channel; if (!reactor->call_ptr && msg_size == sizeof(ptr) && (unsigned long) ptr >= FUSION_SHM_BASE && (unsigned long) ptr < (FUSION_SHM_BASE+FUSION_SHM_SIZE)) dispatch->call_ptr = ptr; else dispatch->call_ptr = reactor->call_ptr; } reactor->dispatch_count++; dev->stat.reactor_dispatch++; fusion_list_foreach (l, reactor->nodes) { ReactorNode *node = (ReactorNode *) l; if (node->fusion_id == fusion_id || node->num_counts <= channel || !node->counts[channel]) continue; if (dispatch) { dispatch->count++; fusionee_send_message (dev, fusionee, node->fusion_id, FMT_REACTOR, reactor->entry.id, channel, msg_size, msg_data, dispatch_callback, dispatch, reactor->entry.id); } else fusionee_send_message (dev, fusionee, node->fusion_id, FMT_REACTOR, reactor->entry.id, channel, msg_size, msg_data, NULL, NULL, 0); } if (dispatch && !dispatch->count) { FusionCallExecute execute; execute.call_id = dispatch->call_id; execute.call_arg = dispatch->call_arg; execute.call_ptr = dispatch->call_ptr; fusion_call_execute( dev, NULL, &execute ); kfree( dispatch ); } fusion_reactor_unlock( reactor ); return 0;}intfusion_reactor_set_dispatch_callback (FusionDev *dev, int id, int call_id, void *call_ptr){ int ret; FusionReactor *reactor; ret = fusion_reactor_lock( &dev->reactor, id, false, &reactor ); if (ret) return ret; if (reactor->destroyed) { fusion_reactor_unlock( reactor ); return -EIDRM; } reactor->call_id = call_id; reactor->call_ptr = call_ptr; fusion_reactor_unlock( reactor ); return 0;}intfusion_reactor_destroy (FusionDev *dev, int id){ int ret; FusionReactor *reactor; ret = fusion_reactor_lock( &dev->reactor, id, true, &reactor ); if (ret) return ret; if (reactor->destroyed) { fusion_reactor_unlock( reactor ); up( &dev->reactor.lock ); return -EIDRM; } reactor->destroyed = true; if (!reactor->nodes) fusion_entry_destroy_locked( &dev->reactor, &reactor->entry ); else fusion_reactor_unlock( reactor ); up( &dev->reactor.lock ); return 0;}voidfusion_reactor_detach_all (FusionDev *dev, FusionID fusion_id){ FusionLink *l, *n; down (&dev->reactor.lock); fusion_list_foreach_safe (l, n, dev->reactor.list) { ReactorNode *node; FusionReactor *reactor = (FusionReactor *) l; down (&reactor->entry.lock); fusion_list_foreach (node, reactor->nodes) { if (node->fusion_id == fusion_id) { fusion_list_remove (&reactor->nodes, &node->link); kfree (node->counts); kfree (node); break; } } if (reactor->destroyed && !reactor->nodes) fusion_entry_destroy_locked( &dev->reactor, &reactor->entry ); else up (&reactor->entry.lock); } up (&dev->reactor.lock);}intfusion_reactor_fork_all (FusionDev *dev, FusionID fusion_id, FusionID from_id){ FusionLink *l; int ret = 0; down (&dev->reactor.lock); fusion_list_foreach (l, dev->reactor.list) { FusionReactor *reactor = (FusionReactor *) l; ret = fork_node (reactor, fusion_id, from_id); if (ret) break; } up (&dev->reactor.lock); return ret;}/******************************************************************************/static intfork_node (FusionReactor *reactor, FusionID fusion_id, FusionID from_id){ ReactorNode *node; down (&reactor->entry.lock); fusion_list_foreach (node, reactor->nodes) { if (node->fusion_id == from_id) { ReactorNode *new_node; new_node = kmalloc (sizeof(ReactorNode), GFP_KERNEL); if (!new_node) { up (&reactor->entry.lock); return -ENOMEM; } new_node->counts = kmalloc (sizeof(int) * node->num_counts, GFP_KERNEL); if (!new_node->counts) { kfree( new_node ); up (&reactor->entry.lock); return -ENOMEM; } new_node->fusion_id = fusion_id; new_node->num_counts = node->num_counts; memcpy( new_node->counts, node->counts, sizeof(int) * node->num_counts ); fusion_list_prepend (&reactor->nodes, &new_node->link); break; } } up (&reactor->entry.lock); return 0;}static voidfree_all_nodes (FusionReactor *reactor){ FusionLink *n; ReactorNode *node; fusion_list_foreach_safe (node, n, reactor->nodes) { kfree (node->counts); kfree (node); } reactor->nodes = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -