Linux那些事儿之我是Hub(大结局)挂起自动化【转】
转自:http://blog.csdn.net/fudan_abc/article/details/1805471
目睹了当今大学校园的素质流氓化,kiss公开化,消费白领化,上课梦游化,逃课普遍化,补考专业化之后,区里的人们很时髦的提出了一个挂起自动化的概念.
接下来的一个话题就是autosuspend/autoresume.
所谓的autosuspend就是driver自己判断是否需要挂起,而之前的suspend/resume是受外界影响的,比如说PM core统一的系统级的挂起,或者用户通过sysfs来触发的.于是我们现在就来看driver是如何自己判断的.首先从autosuspend_check看起,因为这个函数我们已经见过了,只是没有讲,在usb_suspend_both中就会调用它.它来自drivers/usb/core/driver.c:
930 /* Internal routine to check whether we may autosuspend a device. */
931 static int autosuspend_check(struct usb_device *udev)
932 {
933 int i;
934 struct usb_interface *intf;
935 unsigned long suspend_time;
936
937 /* For autosuspend, fail fast if anything is in use or autosuspend
938 * is disabled. Also fail if any interfaces require remote wakeup
939 * but it isn't available.
940 */
941 udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
942 if (udev->pm_usage_cnt > 0)
943 return -EBUSY;
944 if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
945 return -EPERM;
946
947 suspend_time = udev->last_busy + udev->autosuspend_delay;
948 if (udev->actconfig) {
949 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
950 intf = udev->actconfig->interface[i];
951 if (!is_active(intf))
952 continue;
953 if (intf->pm_usage_cnt > 0)
954 return -EBUSY;
955 if (intf->needs_remote_wakeup &&
956 !udev->do_remote_wakeup) {
957 dev_dbg(&udev->dev, "remote wakeup needed "
958 "for autosuspend/n");
959 return -EOPNOTSUPP;
960 }
961 }
962 }
963
964 /* If everything is okay but the device hasn't been idle for long
965 * enough, queue a delayed autosuspend request.
966 */
967 if (time_after(suspend_time, jiffies)) {
968 if (!timer_pending(&udev->autosuspend.timer)) {
969
970 /* The value of jiffies may change between the
971 * time_after() comparison above and the subtraction
972 * below. That's okay; the system behaves sanely
973 * when a timer is registered for the present moment
974 * or for the past.
975 */
976 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
977 suspend_time - jiffies);
978 }
979 return -EAGAIN;
980 }
981 return 0;
982 }
首先, 获得do_remote_wakeup,打不打开remote wakeup的功能是可以选择的.所以每次要记录下来.
pm_usage_cnt表示引用计数,自动挂起的第一个重要条件就是pm_usage_cnt为0.即只有一个设备没有被使用了我们才能把它挂起,否则比如你正在和恋人视频聊天,突然给你挂起,那你肯定会把开源社区的所有人的母亲都给问候一遍.
autosuspend_delay,也是在八大函数之一的usb_alloc_dev中赋的值,默认就是2HZ,当然你可以自己设置,因为它是通过usbcore的模块参数usb_autosuspend_delay来设置的. usb_autosuspend_delay缺省值为2.另外这个值我们也可以通过sysfs来设置,如下所示:
localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # ls /sys/bus/usb/devices/1-1/power/
autosuspend level state wakeup
autosuspend文件就是记录这个值的,以秒为单位.
localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # cat /sys/bus/usb/devices/1-1/power/autosuspend
2
可以看到,我没有设置过的话,它这个值就是2.这个值的意思是如果设备闲置了2s,那么它将被自动挂起,这就是autosuspend的目的,你可以把它设为负值,为负就表示设备不能被autosuspend,如果设备此时正处于suspended状态而你写一个负值进去,它将立刻被唤醒.写个0则表示设备将立刻被autosuspended.
再来看autosuspend_disabled.前面我们有看到一个autoresume_disabled,这两个变量的含义都如字面意义一样.这两个变量都可以通过sysfs来改变,
localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # ls /sys/bus/usb/devices/1-1/power/
autosuspend level state wakeup
这里的这个level就是反映的设备的电源级别,确切的说它就是通过sysfs为用户提供了一个自己挂起设备的方法.
localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # cat /sys/bus/usb/devices/1-1/power/level
auto
它可以为auto/on/suspend,这里我们看到它是auto,auto是最为常见的级别,而on就意味着我们不允许设备进行autosuspend,即autosuspend被disable了,或者说这里的autosuspend_disabled被设置为了1.如果是suspend,就意味着我们不允许设备进行autoresume,并且强迫设备进入suspended状态.即我们设置autoresume_disabled为1,并且调用usb_external_suspend_device()去挂起设备,这就是sysfs提供给用户的suspend单个设备的方法.
而auto状态意味着autosuspend_disabled和autoresume_disabled都没有设置,即都为0,任其自然.
到这里你就能明白为什么我们当初在usb_resume中以及在usb_resume_both中会判断udev->autoresume_disabled了.因为设置了这个flag就等于对resume宣判了死刑.同样这里对udev->autosuspend_disabled的判断也是一样的道理.
last_busy,struct usb_device的成员,unsigned long last_busy,有注释说time of last use,不过我不知道该如何用中文表达,只可意会不能言传.不过没关系,我们慢慢看就明白了,其实你会发现在resume之后会更新它,在suspend之前也会更新它.你搜索一下源代码就会发现,其实这个变量基本上就被赋了一个值,那就是传说中的jiffies,所以它实际上就是记录着这么一个时间值,我们这里947行,给一个局部变量suspend_time赋值,赋的就是udev->last_busy加上udev->autosuspend_delay,我们马上就会看到suspend_time干嘛用的.
948到962行,这一段就是判断各种异常条件,只有这些通通满足了才有必要作autosuspend. 其中,needs_remote_wakeup咱们在hub_probe()中见过,它是struct usb_interface的一个成员,unsigned needs_remote_wakeup,缺省值就是1.咱们在hub_probe中也是设置为1.如果设备需要remote wakeup,而do_remote_wakeup被设置为了0,那么就是说我本来需要被远程唤醒的,你却把我这项功能禁掉了,那么对于这种情况,这里保险起见,就不进行autosuspend了,因为万一把设备催眠了之后唤不醒了那就糟了,省电是省电了,设备醒不过来了,除非重起机器否则没办法了,这就属于捡了芝麻丢了西瓜的情况,咱们当然不能做.
964行的注释说的很明白,如果一切Okay,咱们才进行下面的代码,
这里有两个时间方面的函数,time_after,这个函数返回真如果从时间上来看,第一个参数在第二个参数之后.这里就是说如果suspend_time比jiffies后,我们刚才刚看了suspend_time的赋值,缺省来说suspend_time就比jiffies要多一个autosuspend_delay,即2秒钟,所以这里为真.
第二个函数timer_pending就是判断一个计时器到点了没有,如果没有到点,即所谓的pending状态,那么函数返回真,否则返回0.这里参数是udev->autosuspend.timer,这个东东我们在八大函数之一的usb_alloc_dev中调用INIT_DELAYED_WORK进行了初始化,进一步跟踪会发现实际上是调用init_timer()来初始化timer,而init_timer中timer->entry.next=NULL,我们不用管这句话啥意思,但是我们可以看到,timer_pending就是一个内联函数,来自include/linux/timer.h,
51 /**
52 * timer_pending - is a timer pending?
53 * @timer: the timer in question
54 *
55 * timer_pending will tell whether a given timer is currently pending,
56 * or not. Callers must ensure serialization wrt. other operations done
57 * to this timer, eg. interrupt contexts, or other CPUs on SMP.
58 *
59 * return value: 1 if the timer is pending, 0 if not.
60 */
61 static inline int timer_pending(const struct timer_list * timer)
62 {
63 return timer->entry.next != NULL;
64 }
所以很显然,这个函数将返回0.因为timer->entry.next==NULL.当然,我是说第一次.以后就不一样了. 因为这里queue_delayed_work()会执行,我们前面已经提过,所以这行的意思就很简单了,把udev->autosuspend这个任务加入到ksuspend_usb_wq这个工作队列中去.并且设置了延时suspend_time – jiffies,基本上这就意味着2秒之后就调用udev->autosuspend所对应的函数,即我们在usb_alloc_dev中用INIT_DELAYED_WORK注册的那个函数usb_autosuspend_work函数.因此我们就可以继续看usb_autosuspend_work这个函数了,来自drivers/usb/core/driver.c:
1209 /* usb_autosuspend_work - callback routine to autosuspend a USB device */
1210 void usb_autosuspend_work(struct work_struct *work)
1211 {
1212 struct usb_device *udev =
1213 container_of(work, struct usb_device, autosuspend.work);
1214
1215 usb_autopm_do_device(udev, 0);
1216 }
其实调用的是usb_autopm_do_device,
1182 /* Internal routine to adjust a device's usage counter and change
1183 * its autosuspend state.
1184 */
1185 static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
1186 {
1187 int status = 0;
1188
1189 usb_pm_lock(udev);
1190 udev->auto_pm = 1;
1191 udev->pm_usage_cnt += inc_usage_cnt;
1192 WARN_ON(udev->pm_usage_cnt < 0);
1193 if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
1194 if (udev->state == USB_STATE_SUSPENDED)
1195 status = usb_resume_both(udev);
1196 if (status != 0)
1197 udev->pm_usage_cnt -= inc_usage_cnt;
1198 else if (inc_usage_cnt)
1199 udev->last_busy = jiffies;
1200 } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
1201 if (inc_usage_cnt)
1202 udev->last_busy = jiffies;
1203 status = usb_suspend_both(udev, PMSG_SUSPEND);
1204 }
1205 usb_pm_unlock(udev);
1206 return status;
1207 }
1193行,inc_usage_cnt咱们传递进来的是0,但你会发现有的函数传递进来的是1,比如usb_autoresume_device,有的函数传递进来的是-1,比如usb_autosuspend_device,还有另一个地方, usb_try_autosuspend_device,传递进来的也是0.不过在2.6.22.1的内核中,总共也就这四处调用了usb_autopm_do_device这个函数.所以我们这里一并来看.
对于inc_usage_cnt大于等于0的情况,如果pm_usage_cnt也大于0,那么如果设备此时又处于SUSPENDED状态,那么我们就调用usb_resume_both把它给恢复过来,恢复过来之后,设置last_busy为jiffies,记录下这一神圣的时刻.如果没能恢复,那么就把pm_usage_cnt减回去.
如果inc_usage_cnt小于等于0,如果pm_usage_cnt也小于等于0,那么没什么好说的,把设备给挂起,挂起之前用last_busy记录下设备活着的那一时刻.
由于咱们这个情景传递进来的inc_usage_cnt是0,所以last_busy没有改变.而pm_usage_cnt也没有改变,这就意味着咱们并不做什么引用计数上的改变,只是纯粹的check,如果当前引用计数大于0而设备居然是挂起的状态,那么赶紧唤醒,如果当前引用计数已经小于等于0,那么就自觉地挂起.
于是我们接下来要做的是两件事情,第一个,看一下另外三个调用usb_autopm_do_device的函数,第二个,回到usb_suspend_both中去看一下autosuspend_check是在什么情景下被调用的.
先看第二个问题,回过头来看usb_suspend_both,发现,1042行和1068行,如果udev->auto_pm不为0,就调用autosuspend_check,而auto_pm不为0恰恰是在usb_autopm_do_device中设置的,比如这里的1190行,还有一种可能是在usb_autopm_do_interface中设置的.后者我们暂时先不看.
调用usb_suspend_both的地方总共有三处,usb_autopm_do_device/usb_autopm_do_interface/usb_external_suspend_device,很显然,前两者属于同一情况,它们属于autosuspend/autoresume类型的,第三者属于另一种情况,它属于对非autosuspend的支持,即对PM core或者sysfs接口的支持.在usb_external_suspend_device中,调用usb_suspend_both之前先设置了auto_pm为0.
所以,对于autosuspend,usb_suspend_both首先会调用autosuspend_check,进而usb_autopm_do_device会被调用,而后者又会根据实际情况调用usb_suspend_both或者usb_resume_both.
而对于非autosuspend,usb_suspend_both虽然也会被调用,但是autosuspend_check是不会执行的.
那么我们现在来看是另外三种调用usb_autopm_do_device的情况.三个函数全都来自drivers/usb/core/driver.c:
1218 /**
1219 * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
1220 * @udev: the usb_device to autosuspend
1221 *
1222 * This routine should be called when a core subsystem is finished using
1223 * @udev and wants to allow it to autosuspend. Examples would be when
1224 * @udev's device file in usbfs is closed or after a configuration change.
1225 *
1226 * @udev's usage counter is decremented. If it or any of the usage counters
1227 * for an active interface is greater than 0, no autosuspend request will be
1228 * queued. (If an interface driver does not support autosuspend then its
1229 * usage counter is permanently positive.) Furthermore, if an interface
1230 * driver requires remote-wakeup capability during autosuspend but remote
1231 * wakeup is disabled, the autosuspend will fail.
1232 *
1233 * Often the caller will hold @udev's device lock, but this is not
1234 * necessary.
1235 *
1236 * This routine can run only in process context.
1237 */
1238 void usb_autosuspend_device(struct usb_device *udev)
1239 {
1240 int status;
1241
1242 status = usb_autopm_do_device(udev, -1);
1243 // dev_dbg(&udev->dev, "%s: cnt %d/n",
1244 // __FUNCTION__, udev->pm_usage_cnt);
1245 }
1246
1247 /**
1248 * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces
1249 * @udev: the usb_device to autosuspend
1250 *
1251 * This routine should be called when a core subsystem thinks @udev may
1252 * be ready to autosuspend.
1253 *
1254 * @udev's usage counter left unchanged. If it or any of the usage counters
1255 * for an active interface is greater than 0, or autosuspend is not allowed
1256 * for any other reason, no autosuspend request will be queued.
1257 *
1258 * This routine can run only in process context.
1259 */
1260 void usb_try_autosuspend_device(struct usb_device *udev)
1261 {
1262 usb_autopm_do_device(udev, 0);
1263 // dev_dbg(&udev->dev, "%s: cnt %d/n",
1264 // __FUNCTION__, udev->pm_usage_cnt);
1265 }
1266
1267 /**
1268 * usb_autoresume_device - immediately autoresume a USB device and its interfaces
1269 * @udev: the usb_device to autoresume
1270 *
1271 * This routine should be called when a core subsystem wants to use @udev
1272 * and needs to guarantee that it is not suspended. No autosuspend will
1273 * occur until usb_autosuspend_device is called. (Note that this will not
1274 * prevent suspend events originating in the PM core.) Examples would be
1275 * when @udev's device file in usbfs is opened or when a remote-wakeup
1276 * request is received.
1277 *
1278 * @udev's usage counter is incremented to prevent subsequent autosuspends.
1279 * However if the autoresume fails then the usage counter is re-decremented.
1280 *
1281 * Often the caller will hold @udev's device lock, but this is not
1282 * necessary (and attempting it might cause deadlock).
1283 *
1284 * This routine can run only in process context.
1285 */
1286 int usb_autoresume_device(struct usb_device *udev)
1287 {
1288 int status;
1289
1290 status = usb_autopm_do_device(udev, 1);
1291 // dev_dbg(&udev->dev, "%s: status %d cnt %d/n",
1292 // __FUNCTION__, status, udev->pm_usage_cnt);
1293 return status;
1294 }
不看不知道,一看吓一跳,竟然都是如此赤裸裸的调用usb_autopm_do_device函数,用黎叔的话说,那叫一点儿技术含量都没有!
不过调用这三个函数的地方却很多很多.甚至我们都曾经见过,比如在usb_suspend_both中就调用了usb_autosuspend_device,用它来挂起父设备.即有这么一种可能,usb_autosuspend_device调用usb_suspend_both挂起当前设备,而usb_suspend_both则调用autosuspend_check并进而是usb_autopm_do_device去挂起当前设备,而usb_autopm_do_device又还是调用usb_suspend_both去挂起设备,咦,怎么看怎么觉得我们走进了一个迷宫,走进了一条死胡同.很明显的是你调用我我调用你,这还不挂了?其实您尽管放心,别以为写代码的兄弟们都是吃素的,事实上有一把锁专门来对付这些情况,我们看到,在usb_external_suspend_device中调用usb_suspend_both的前后,调用了这两个函数:usb_pm_lock/usb_pm_unlock,在usb_external_resume_device中,调用usb_resume_both前后也是如此,而在usb_autopm_do_device和usb_autopm_do_interface中,也需要使用这些两个函数,即只有获得了这把锁才能去调用usb_resume_both或者usb_suspend_both.所以,你尽管放心,永远只有一个人能执行usb_suspend_both或者usb_resume_both,绝不可能陷入所谓的死胡同.所以其实你也看出来了,对于挂起,无论是不是自动化,里面终不过围绕一个函数,usb_suspend_both,对于唤醒,无论是不是自动化,里面终不过围绕一个函数,usb_resume_both,就好比,无论男人给女人讲多么浪漫的童话故事,里面终不过围绕一个字:床!
我想现在是时候来做一次总结了,关于电源管理方面的总结,先说autosuspend,我们来看对usb_try_autosuspend_device的调用,前面我们在usb_external_resume_device中就看见了对它的调用,唤醒了设备之后,就尝试着看是否可以自动挂起.这其实体现的是一种勤俭节约的理念,因为autosuspend/autoresume这东西吧,纯粹是一种软件角度的主动,即从driver这边来自己做判断,凭借着第六感,当它觉得应该挂起设备的时候,它就会去尝试调用相关的挂起函数,当它觉得应该唤醒设备的时候,它就会去调用相关的唤醒函数.
那么也就是说,在整个USB子系统里,对电源管理的支持是按照两步走的.头些年,我们先实现传统的挂起/唤醒,即比如合上笔记本的时候,PM core那边会按设备树来依次调用各个驱动的suspend函数,醒来的时候则调用相应的resume函数.于是从整个usb子系统的角度来说,我们提供了usb_suspend/usb_resume这两个函数.另一方面,我们这里把函数取名为usb_external_suspend_device和usb_external_resume_device也是针对PM core的系统睡眠(System Sleep),即我们把来自PM core的挂起请求/唤醒请求称为外部请求.而usb_suspend/usb_resume内部所调用的正是这两个函数.另一种调用usb_external_suspend_device/usb_external_resume_device的情况是通过sysfs的接口,由用户来触发,即通过改变前面我们看到的sysfs下面那个level的值来触发挂起或者唤醒.
完了后来第二步,大家觉得光这样不过瘾,于是又引入了autosuspend的概念.就是说驱动程序在适当的位置,自己去调用那些挂起函数/唤醒函数.即便PM core那边没有这个需求.就比如刚才这里这个对usb_try_autosuspend_device的调用,即设备刚刚唤醒,驱动程序就去检查看看是否可以挂起设备,因为可能你不小心唤醒了它但是你也许并不使用它,那么从省电的角度来说,驱动程序有足够的理由再次把你挂起.而像这种情形有很多,我们只要搜索一下看看有多少地方调用了usb_autosuspend_device/usb_autoresume_device就可以知道,在许多地方我们都这么做了.现以我们前面见过但没有讲的一个地方为例子说一下:
当初我们在usb_reset_composite_device中看到的,3076行我们调用了usb_autoresume_device,而3119行我们调用了usb_autosuspend_device.后者很好理解,把一个设备reset之后,首先就去尝试把它挂起,理由很简单,比如你开机之后,你可能只是开机,你根本没打算使用任何usb设备,那么usb这边就默认把所有的设备都给挂起.等你真正要用的时候再去唤醒.而前者的目的更加简单,就是为了阻止后者的执行,因为这两个函数都将会调用usb_autopm_do_device,而那句usb_pm_lock注定了这是一条独木桥,有你就没有我,有我便没有你.
最后再来关注一个变量,last_busy.它正是为autosuspend而生的.我们不难发现,每次设备被唤醒之后我们会把last_busy设置为当时的jiffies,每次设备将要被挂起之前我们会把last_busy设置为当时的jiffies.而真正要利用last_busy的是autosuspend_check函数,因为在该函数内,suspend_time被赋值为last_busy加上autosuspend_delay,假设后者为2s.那么就是说suspend_time为last_busy加上2秒.比如说我们记录下上次设备被使用的时候last_busy为3点25分0秒,而现在是北京时间3点25分1秒,那么我们调用autosuspend_check的话就会激发一次与之相关的函数usb_autosuspend_work.反之如果现在已经是北京时间4点了,那么说明我们已经没有必要激发usb_autosuspend_work了.换言之,last_busy就是被用来决定是否进行autosuspend的一个flag.last_busy记录的是设备正忙的时间,设备总是在闲置了足够长的时间才可以被挂起.很显然,没有last_busy,这个autosuspend_delay也就没法起作用了,毕竟这个2s总要在一个时间起点上开始加上去.当然,last_busy和suspend_time这两个变量也只是几个月前才被加入到内核中来的,以前的内核中并没有这么两个变量.当时Alan大侠添加这个变量的目的是为了完善他的autosuspend.喜欢考古的朋友们不难从今年3月底linux-usb-devel邮件列表里挖出他当时的陈述:
This patch (as877) adds a "last_busy" field to struct usb_device, for
use by the autosuspend framework. Now if an autosuspend call comes at
a time when the device isn't busy but hasn't yet been idle for long
enough, the timer can be set to exactly the desired value. And we
will be ready to handle things like HID drivers, which can't maintain
a useful usage count and must rely on the time-of-last-use to decide
when to autosuspend.
用中文来说,就是两个理由要加入这么一个变量,一个是比如autosuspend调用发生的时候,它希望知道设备是否忙,用充分必要条件理论来说,设备不忙是autosuspend的必要条件,但这个必要条件满足了并不意味着设备会马上挂起,因为我们有一个autosuspend_delay,即我们可以设置延时,如果按默认的2s钟来说,那你设备至少要闲置了2秒钟才会被挂起.所以就需要这么一个flag,经常去记录着某个时间点,比如我们在autoresume之后的那一瞬间,又比如我们在autosuspend之前的一瞬间.道理很简单,第一,设备醒来之后那一瞬间基本上可以认为是忙的,如果不忙它干嘛不继续睡?第二,设备睡觉之前那一瞬间基本上也可以认为是忙的,如果不忙干嘛不早点睡?
引入last_busy的第二个理由是为了HID设备驱动的,比如鼠标,键盘.因为它们的挂起需要用一个时间来判断.不过我说过了,autosuspend是一个很新的理念,所以至少到2.6.22.1的内核中,HID那边还没有提供对autosuspend足够的支持,但是相信在不久的将来last_busy会被HID Drivers用到的.我们拿触摸屏来举例,我们知道苹果的ipod系列很多都是有触摸屏的,那么从驱动程序的角度来说呢,所谓的autosuspend,理想情况就是,driver能够检测到你的手指离开了触摸屏,然后隔一段时间driver就可以把设备自动挂起,反过来,driver一旦检测到你的手指回来了,它又把设备唤醒.
网友”丰胸化吉”问我,那为何last_busy记录的是resume之后以及suspend之前的时间,而不是记录别的时间?这其实无所谓,你想多记录几个也没人拦住你,记录这几个时间的作用就是让autosuspend能在它们之后的两秒之后再执行,并没有更多的意思.你要是觉得某个地方之后不能立刻被挂起,那么你也可以在该处记录一个last_busy.不过目前来看其它地方似乎并没有这个需求罢了.
好了,我的故事又讲完了.我知道,我并非是刻意追求娱乐技术化或者技术娱乐化,或许我只是在写一个北漂人的无奈,又或许我只是借文字以寻觅自己的未来.此时此刻,电台里放起了赵传的我是一只小小鸟,耳边响起了那耐人寻味的歌词:有时候我觉得自己是一只小小鸟,想要飞却怎么也飞不高,也许有一天我攀上了枝头(读完了大学)却成为住不起房子的人,飞上了青天(来到了北京)才发现自己从此无依无靠...每次到了夜深人静的时候我总是睡不着,我怀疑是不是只有我的明天没有变得更好,未来会怎样究竟有谁会知道,幸福是否只是一种传说我永远都找不到...
Linux那些事儿之我是Hub(大结局)挂起自动化【转】的更多相关文章
- Windows Phone开发(45):推送通知大结局——Raw通知
原文:Windows Phone开发(45):推送通知大结局--Raw通知 为什么叫大结局呢?因为推送通知服务就只有三种,前面扯了两种,就剩下一种--Raw通知. 前面我们通过两节的动手实验,相信大家 ...
- AFO 我的oi生涯 大结局
今儿个哥几个一屋子退役了,这两天也许会写一个生涯大结局留作纪念吧. 今天就写了吧. 由于在机房的原因比一般同学获得的知识更多一些.进来总是看新闻,感慨颇多.自从两会开的第一天起,我就对我们政府采取的一 ...
- Java匹马行天下之Java帝国的崛起(大结局)
Java匹马行天下之Java帝国的崛起大结局 前言: [博客*缘] 网络真情伴, 博客友谊连. 笑中藏泪暖中寒. 回想那些悲喜, 苦涩也缠绵. 往事难回首, 新篇染旧言. 世间多少梦能全. 感谢相牵, ...
- linux下使用split 来分割大文件
linux下使用split 来分割大文件 2010-07-27 15:46:27| 分类: 技术文稿 | 标签:split 分割 linux |字号 订阅 平常都是使用ssh来进行远程 ...
- AC的故事大结局山寨版(下)(最大流)
福建工程学院第十二届ACM程序设计大赛真题 AC的故事大结局山寨版(下) TimeLimit:2000MS MemoryLimit:128MB 64-bit integer IO format:%l ...
- AC的故事大结局山寨版(下)
AC的故事大结局山寨版(下) TimeLimit:2000MS MemoryLimit:128MB 64-bit integer IO format:%lld Problem Descripti ...
- 实力封装:Unity打包AssetBundle(大结局)
→→前情提要:让用户选择要打包的文件←← 大结局:更多选择 Unity打包AssetBundle从入门到放弃系列终于要迎来大结局了[小哥哥表示实在写不动了o(╥﹏╥)o]... 经过上一次的教程,其实 ...
- 利用Linux的硬连接删除MySQL大文件
利用Linux的硬连接删除MySQL大文件 http://blog.csdn.net/wxliu1989/article/details/22895201 原理:硬链接基础当多个文件共同指向同一ino ...
- MySQL☞大结局
emmm,看了这么多大概会用了点点,学到了一点点 select 列名/*/聚合函数 from 表名1 别名1 连接查询(左外.右外等等) 表名2 别名2 on 关联条件 where 查询条件 g ...
随机推荐
- 编码用命令行执行的C语言词语统计程序
需求介绍 程序处理用户需求的模式为: wc.exe [parameter][filename] 在[parameter]中,用户通过输入参数与程序交互,需实现的功能如下: 1.基本功能 支持 -c ...
- php多进程pcntl学习(一)
pcntl在windows下无法使用,linux编译php时加上参数--enable-pcntl 即可.第一次使用pcntl模块,遇到了一些坑也慢慢填上了,这里简单记录下. 1. 子进程之间变量无法共 ...
- Android Tab类型主界面 Fragment+TabPageIndicator+ViewPager
文章地址: Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager 1.使用ViewPager + PagerAdapter 每个页面的内容都 ...
- python 按照固定长度分割字符串
>>> import re >>> string = '123456789abcdefg' >>> re.findall(r'.{3}', str ...
- SQL 中LTrim、RTrim与Trim的用法
LTrim.RTrim与 Trim 函数 返回 Variant (String),其中包含指定字符串的拷贝,没有前导空白 (LTrim).尾随空白 (RTrim) 或前导和尾随空白 (Trim).语法 ...
- 一本通1628X-factor Chain
1628:X-factor Chain 时间限制: 1000 ms 内存限制: 524288 KB [题目描述] 原题来自 POJ 3421 输入正整数 x,求 x 的大于 1 的因子 ...
- 【loj6029】「雅礼集训 2017 Day1」市场 线段树+均摊分析
题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有四种:区间加.区间下取整除.区间求最小值.区间求和. $n\le 100000$ ,每次加的数在 $[-10^4,10^4]$ 之 ...
- [JZOJ 5402] God Knows
终于搞完了这乡里别题目 $ $ 考虑一个 \(dp\) ,设 \(f[i]\) 表示最后一个匹配选 \((i,p[i])\) 的最小费用 首先我们考虑答案长什么样 假设根据 \(p[i]\) 排序 , ...
- suoi22 WRX知识树(dfs序)
把一条路径拆成到根的四个链(两端点.lca和fa[lca]),然后给dfs序中链的端点做单点修改.区间查询它的子树和再加上它原来的权值就可以了 #include<bits/stdc++.h> ...
- luogu2679 [NOIp2015]子串 (dp)
设f[i][j][k][b]表示在A串第i位.这是第j组.B串第k位.i号选不选(b=0/1) 那么就有$f[i][j][k][1]=(A[i]==B[k])*(f[i-1][j-1][k][0]+f ...