1. 程式人生 > >linux核心kobject事件處理詳解

linux核心kobject事件處理詳解

/*所有事件的名稱列表*/
static const char *kobject_actions[] = {
	[KOBJ_ADD] =		"add",
	[KOBJ_REMOVE] =		"remove",
	[KOBJ_CHANGE] =		"change",
	[KOBJ_MOVE] =		"move",
	[KOBJ_ONLINE] =		"online",
	[KOBJ_OFFLINE] =	"offline",
};

/*用於事件處理的函式列表*/
struct kset_uevent_ops {
	/*事件過濾器,返回0表示不用向用戶空間報告事件*/
	int (* const filter)(struct kset *kset, struct kobject *kobj);
	/*返回子系統的名字*/
	const char *(* const name)(struct kset *kset, struct kobject *kobj);
	/*新增子系統特有的環境變數*/
	int (* const uevent)(struct kset *kset, struct kobject *kobj,
		      struct kobj_uevent_env *env);
}

/*核心表示的環境*/
struct kobj_uevent_env {
	//環境變數/值陣列
	char *envp[UEVENT_NUM_ENVP];
	//當前環境變數值索引
	int envp_idx;
	//環境資料緩衝區
	char buf[UEVENT_BUFFER_SIZE];
	//環境資料緩衝區的長度
	int buflen;
};


/**
 * kobject_uevent_env - send an uevent with environmental data
 *
 * @action: action that is happening
 * @kobj: struct kobject that the action is happening to
 * @envp_ext: pointer to environmental data
 *
 * Returns 0 if kobject_uevent() is completed with success or the
 * corresponding error when it fails.
 */
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
		       char *envp_ext[])
{
	struct kobj_uevent_env *env;
	//獲得事件的名稱
	const char *action_string = kobject_actions[action];
	const char *devpath = NULL;
	const char *subsystem;
	struct kobject *top_kobj;
	struct kset *kset;
	const struct kset_uevent_ops *uevent_ops;
	u64 seq;
	int i = 0;
	int retval = 0;

	pr_debug("kobject: '%s' (%p): %s\n",
		 kobject_name(kobj), kobj, __func__);

	/* search the kset we belong to */
	/*向上尋找所屬的kset*/
	top_kobj = kobj;
	while (!top_kobj->kset && top_kobj->parent)
		top_kobj = top_kobj->parent;

	if (!top_kobj->kset) {
		pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
			 "without kset!\n", kobject_name(kobj), kobj,
			 __func__);
		return -EINVAL;
	}
	/*找到了kset獲得事件處理列表*/
	kset = top_kobj->kset;
	uevent_ops = kset->uevent_ops;

	/* skip the event, if uevent_suppress is set*/
	/*事件被抑制*/
	if (kobj->uevent_suppress) {
		pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
				 "caused the event to drop!\n",
				 kobject_name(kobj), kobj, __func__);
		return 0;
	}
	/* skip the event, if the filter returns zero. */
	/*事件被過濾掉*/
	if (uevent_ops && uevent_ops->filter)
		if (!uevent_ops->filter(kset, kobj)) {
			pr_debug("kobject: '%s' (%p): %s: filter function "
				 "caused the event to drop!\n",
				 kobject_name(kobj), kobj, __func__);
			return 0;
		}

	/* originating subsystem */
	/*獲得當前子系統的名字*/
	if (uevent_ops && uevent_ops->name)
		subsystem = uevent_ops->name(kset, kobj);
	else
		subsystem = kobject_name(&kset->kobj);
	/*無法獲得子系統的名字*/
	if (!subsystem) {
		pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
			 "event to drop!\n", kobject_name(kobj), kobj,
			 __func__);
		return 0;
	}

	/* environment buffer */
	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
	if (!env)
		return -ENOMEM;

	/* complete object path */
	/*獲得kobject的路徑*/
	devpath = kobject_get_path(kobj, GFP_KERNEL);
	if (!devpath) {
		retval = -ENOENT;
		goto exit;
	}

	/* default keys */
	/*來,開始新增環境變數/值對*/
	retval = add_uevent_var(env, "ACTION=%s", action_string);
	if (retval)
		goto exit;
	retval = add_uevent_var(env, "DEVPATH=%s", devpath);
	if (retval)
		goto exit;
	retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
	if (retval)
		goto exit;

	/* keys passed in from the caller */
	if (envp_ext) {
		for (i = 0; envp_ext[i]; i++) {
			retval = add_uevent_var(env, "%s", envp_ext[i]);
			if (retval)
				goto exit;
		}
	}

	/* let the kset specific function add its stuff */
	/*新增外部環境變數*/
	if (uevent_ops && uevent_ops->uevent) {
		retval = uevent_ops->uevent(kset, kobj, env);
		if (retval) {
			pr_debug("kobject: '%s' (%p): %s: uevent() returned "
				 "%d\n", kobject_name(kobj), kobj,
				 __func__, retval);
			goto exit;
		}
	}

	/*
	 * Mark "add" and "remove" events in the object to ensure proper
	 * events to userspace during automatic cleanup. If the object did
	 * send an "add" event, "remove" will automatically generated by
	 * the core, if not already done by the caller.
	 */
	 /*新增標記啊*/
	if (action == KOBJ_ADD)
		kobj->state_add_uevent_sent = 1;
	else if (action == KOBJ_REMOVE)
		kobj->state_remove_uevent_sent = 1;

	/* we will send an event, so request a new sequence number */
	/*來一個序列號,正版無憂*/
	spin_lock(&sequence_lock);
	seq = ++uevent_seqnum;
	spin_unlock(&sequence_lock);
	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
	if (retval)
		goto exit;

	//來,使用netlink機制,廣播到到使用者空間
#if defined(CONFIG_NET)
	/* send netlink message */
	if (uevent_sock) {
		struct sk_buff *skb;
		size_t len;

		/* allocate message with the maximum possible size */
		len = strlen(action_string) + strlen(devpath) + 2;
		skb = alloc_skb(len + env->buflen, GFP_KERNEL);
		if (skb) {
			char *scratch;

			/* add header */
			scratch = skb_put(skb, len);
			sprintf(scratch, "%
[email protected]
%s", action_string, devpath); /* copy keys to our continuous event payload buffer */ for (i = 0; i < env->envp_idx; i++) { len = strlen(env->envp[i]) + 1; scratch = skb_put(skb, len); strcpy(scratch, env->envp[i]); } NETLINK_CB(skb).dst_group = 1; retval = netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL); /* ENOBUFS should be handled in userspace */ if (retval == -ENOBUFS) retval = 0; } else retval = -ENOMEM; } #endif /* call uevent_helper, usually only enabled during early boot */ if (uevent_helper[0]) { char *argv [3]; argv [0] = uevent_helper; argv [1] = (char *)subsystem; argv [2] = NULL; retval = add_uevent_var(env, "HOME=/"); if (retval) goto exit; retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); if (retval) goto exit; retval = call_usermodehelper(argv[0], argv, env->envp, UMH_WAIT_EXEC); } exit: kfree(devpath); kfree(env); return retval; }

相關推薦

linux核心kobject事件處理

/*所有事件的名稱列表*/ static const char *kobject_actions[] = { [KOBJ_ADD] = "add", [KOBJ_REMOVE] = "remove", [KOBJ_CHANGE] = "change", [KO

可能是最詳細的Android點選事件處理(三)

前兩篇文章: 可能是最詳細的Android點選事件處理詳解 可能是最詳細的Android點選事件處理詳解(二) 這裡再次延伸一下,在ScrollView和RecyclerView巢狀中touch事件的傳遞過程,以及巢狀滑動衝突的問題。 如上圖,外層是一個Neste

可能是最詳細的Android點選事件處理(二)

上一篇我們主要詳細描述了touch事件在各層的傳遞 本篇文章主要是對比touch在不可滾動和可滾動的ViewGroup事件的傳遞過程 如上圖: - 左圖:是ViewGroup巢狀View,不可滑動 - 右圖:也是ViewGroup(RecyclerView)巢

可能是最詳細的Android點選事件處理

面試的時候,很多時候都會問到Touch事件的傳遞,而且問法角度都有所不同,但是還是會遵循基本的事件傳遞規則的,可能他問的你沒處理過,但是根據基本規則慢慢思考來回答,都不會錯。 一,簡介 首先我們知道touch事件 主要是是在三個方法中傳遞和處理的。分別是:

Linux核心Power_Management之suspend

1.Linux核心的suspend狀態 Linux核心支援多種型別睡眠狀態,目前存在四種模式:suspend to idle(freeze)、power-on standby(standb)、suspend to ram(memory;STR)和suspend to dis

Linux核心原始碼目錄結構

    3.1 Linux核心原始碼目錄如下:         /arch:目錄包括了所有和體系結構相關的核心程式碼。它下面的每一個子目錄都代表一種Linux支援的體系結構,例如i386就是Intel

Linux核心模組(驅動)編譯

本文主要說說如何編譯自己開發的核心模組。由於驅動通常也被編譯成核心模組,因此文章的內容也適用於驅動的編譯。 由於在下能力相當有限,有不當之處,還望大家批評指正^_^ 一、準備工作 準備工作如何做,

Linux核心的Oops問題

參考:Linux:  How To Locate An Oops 什麼是Oops?從語言學的角度說,Oops應該是一個擬聲詞。當出了點小事故,或者做了比較尷尬的事之後,你可以說"Oops",翻譯成中國話就叫做“哎呦”。“哎呦,對不起,對不起,我真不是故意打碎

編譯U-boot和Linux核心的步驟和

1、準備材料 linux核心和uboot的原始碼包—- 6818GEC.tar.gz 環境:VMware12.0 Ubuntu16.04(64位) (1)先將 6818GEC.tar.gz 放在Ubuntu的共享目錄下,然後將 68

linux核心之程序管理

1、程序描述符 (1)程序與執行緒          程序是處於執行期的程式以及相關資源的總稱。執行緒在linux上稱為輕量級程序,沒有獨立的地址空間,一個程序下的所有執行緒共享地址空間、檔案系統資源、檔案描述符、訊號處理程式等。 (2)程序描述符task_struct

React-事件處理

對於使用者介面而言,展示只佔整體設計因素的一半,另一半則是相應使用者輸入,即通過JavaScript處理使用者產生的事件。 React通過將事件處理器 繫結到組建上處理事件,事件觸發的同時更新組建的內部狀態,內部狀態更新會觸發元件的重繪。因此,如果檢視層想要渲染出事件出發後

android 開發 View _14 MotionEvent和事件處理,與實踐自定義滑動條View

MotionEvent MotionEvent物件是與使用者觸控相關的時間序列,該序列從使用者首次觸控式螢幕幕開始,經歷手指在螢幕表面的任何移動,直到手指離開螢幕時結束。手指的初次觸控(ACTION_DOWN操作),滑動(ACTION_MOVE操作)和擡起(ACTION

Android熱插拔事件處理

        整個過程從Kernel檢測到SD卡插入事件開始,之前的一些硬體中斷的觸發以及driver的載入這裡並不敘述,一直到SD卡掛載訊息更新到“Android——系統設定——儲存”一項中。        1.    Kernel發出SD卡插入uevent。        2.    Netlink

Linux核心之定時器

static struct pin_desc *irq_pd; /* 鍵值: 按下時, 0x01, 0x02, 0x03, 0x04 */ /* 鍵值: 鬆開時, 0x81, 0x82, 0x83, 0x84 */ static unsigned char key_val; struct pin_desc{u

Linux核心模組程式設計與核心模組LICENSE -《(第3版)》預讀

Linux核心模組簡介Linux核心的整體結構已經非常龐大,而其包含的元件也非常多。我們怎樣把需要的部分都包含在核心中呢?一種方法是把所有需要的功能都編譯到Linux核心。這會導致兩個問題,一是生成的核心會很大,二是如果我們要在現有的核心中新增或刪除功能,將不得不重新編譯核心

Linux kernel核心編譯配置選項

Code maturity level options 程式碼成熟度選項 Prompt for development and/or incomplete code/drivers  顯示尚在開發中或尚未完成的程式碼與驅動.除非你是測試人員或者開發者,否則請勿選擇 G

Elasticsearch基本概念及核心配置文件

last log4j 強烈 內存 文檔 size oca 機制 集群   Elasticsearch5.X,下列的是Elasticsearch2.X系類配置,其實很多配置都是相互兼容的 1. 配置文件 config/elasticsearch.yml 主配置文件

Linux的SOCKET編程(轉)

readv lose 服務 網絡字節序 返回值 quest avi 取數 key Linux的SOCKET編程詳解 1. 網絡中進程之間如何通信 進 程通信的概念最初來源於單機系統。由於每個進程都在自己的地址範圍內運行,為保證兩個相互通信的進 程之間既互不幹擾又

Linux基礎命令(之一)

linux 基礎命令 Linux基礎命令(之一)詳解學習linux的朋友都知道,系統大多數操作都是命令行的操作方式,當然如今也有圖形化界面的操作方式,但是多數情況下仍然使用命令的操作模式,所以命令的作用與用法是成為學好、學會Linux系統的必備前提,也是重點之一,所以今天來聊一聊一些基礎命令的用法與其

springmvc請求處理

控制器 接口 Spring Web MVC 處理的大致過程: 一旦到來,DispatcherSevlet將負責將請求分發。DispatcherServlet可以認為是Spring提供的前端控制器,所有的請求都有經過它來統一分發。 在DispatcherServlet將請求分發給Spring Contr