Step 1. svnadmin create
Run once
@echo off echo --------------------------------------------------------------------------- echo %date:~0,10% %time% echo Start... echo Creating myrep... svnadmin create myrep echo End. echo ---------------------------------------------------------------------------
Step 2. svnsync init
Run once
@echo off echo --------------------------------------------------------------------------- echo %date:~0,10% %time% echo Start... echo Initing myrepo... svnsync init file:///E:/Repositories/myrepo http://ip/svn/myrepo --usernmae me --password * echo End. echo ---------------------------------------------------------------------------
Step 3. svnsync sync
Run whenver you want
@echo off echo --------------------------------------------------------------------------- echo %date:~0,10% %time% echo Start... echo Syncing myrepo... svnsync sync file:///E:/Repositories/myrepo echo End. echo ---------------------------------------------------------------------------
结构化异常处理SEH:__finally终止处理。
结构化异常处理(Structuredexception handling)简称SEH。是windows系统提供的异常处理机制。促使windows将SEH加入到windows系统的一个关键原因就是:它可以简化操作系统本身的开发工作,同时还让系统更加健壮。
我们当然也可以在我们的程序中添加SEH机制,这样我们的应用程序也可以变得更加健壮。使用SEH,我们在编写代码时可以先集中精力完成软件的正常工作流程。也就是说将软件主要功能编写和软件异常处理这两个任务分离开,最后再去处理软件可能遇到的各种错误情况。
为了实现SEH,编译器完成了很多的工作。在进入和离开异常处理代码时编译器会插入一些额外的代码,有时这会导致很大的开销。后面的文章我会介绍编译器都是做了哪些工作。
虽然不同的厂商按照不同的方式来实现SEH,但是大部分的编译厂商都遵循了microsoft的语法规则。因此本文我们将介绍Microsoft visualC++编译器规定的语法。
SEH包括两个方面的内容:终止处理和异常处理。本文我们介绍终止处理,下一篇文章将介绍异常处理。
终止处理
终止处理程序确保无论一个代码块是如何退出的,都能保证该终止处理程序能够被执行。其语法如下:
__try { //被保护的代码。 } __finally//终止处理。 { //终止处理代码。 }
注意:try和finally前都有两个下划线。
终止程序也分为两个部分:__try块为中止处理程序要保护的代码。无论程序以何种方式从该块中退出(如return、goto等语句),__finally块都会被执行。
__finally块为终止处理程序块,该块中的代码会在控制流从__try块退出后、程序结束之前被调用。一般用来执行一些清理操作,如释放资源、释放占有的互斥量等。
但是上面所说的”无论何种方式“有些绝对。因为这个世界本来就没有绝对的东西。当在try块中使用了ExitProcess、ExitThread、TerminateProcess、TerminateThread来终止线程或进程时,finally块就不会被调用。要特别注意这些例外,禁止在try块中使用这些函数。
下面通过代码给大家讲解终止处理程序的使用:
__try { WaitForSingleObject(hMutex,INFINITE); if(x==false) return-1; } __finally { ReleaseMutex(hMutex); return -2; } return 0;
可以看到上面的代码在try中首先等待互斥量内核对象被触发,等待成功后互斥量就属于该线程所有。如果此时执行return-1,则该线程结束,就会导致互斥量对象一直被占有的情况的发生,其他线程会一直处于等待状态。这就是所谓的资源泄漏。有了finally块的保护后,当执行return-1程序试图退出try块时,编译器会让finally块在return之前执行,同时在return(其他语句,如goto等语句也一样)语句之前插入一些代码。return的返回值会被保存在一个临时变量中。
但上面的代码程序的返回值是多少呢?是-1,还是-2呢?答案是-2。当编译器在try块中检测到return语句时,虽然会生成一些代码将返回值保存在一个临时变量中。但是由于finally块代码中也有一个return,finally块中return的值会将原来的返回值覆盖。所以函数最终返回-2。
这个过程被称为局部展开。局部展开会在系统因为try块中的代码提前退出时发生。局部展开会导致非常大的额外开销,因为编译器必须插入代码来保证finally块在程序退出之前执行。最理想的情况就是代码控制流正常的离开try块而进入到finally块中,这时的额外开销最小。在x86体系下离开try块正常进入到finally块只需要执行一条指令。
因此为了将性能开销降到最低,我们改进了上面的代码:
__try { WaitForSingleObject(hMutex,INFINITE); if(x==false) gotoEndOfTryBlock; //一些代码。 EndOfTryBlock: } __finally { ReleaseMutex(hMutex); return -2; } return 0;
在上面改进后的代码中,当在try块中检查到错误发生时不再直接调用return强制退出。而是执行了一条goto语句到try块的末尾。执行此跳转后,控制流从try块中正常退出,直接进入到finally块中。由于没有发生局部展开,编译器不需要插入额外指令,也就没有导致额外的开销。
由于goto语句会破坏程序的执行流程,很多书上都再三强调禁止使用goto。其实我们也没有必要使用goto,因为microsoft提供给我们一个关键字_leave,也可以执行类似的操作。关键字_leave会导致代码执行控制流跳转到try块的末尾,从而代码将正常的从try块进入到finally块中。
下面为使用__leave关键字的改进代码:
__try { WaitForSingleObject(hMutex,INFINITE); if(x==false) __leave //一些代码。 } __finally { ReleaseMutex(hMutex); return -2; } return 0;
本章开头曾介绍过使用SEH可以让程序员将程序正常执行流程和错误处理分开。下面我们分别展示两个例子,一个没有使用SEH,而另一个使用SEH,看下它们到底有何差别,通过比较我们也可以更好的知道SEH是如何完成上述工作的。
下面是没有使用SEH的程序:
bool fun(char* fileName) { HANDLEhFile=CreateFile(....); if(hFile==INVALID_HANDLE_VALUE) { returnfalse; } HANDLEhFileMapping=CreateFileMapping(...); if(hFile==NULL) { CloseHandle(hFile); returnfalse; } char*p=MapViewOfFile(..); if(p==NULL) { CloseHandle(hFile); CloseHandle(hFileMapping); return false; } //其他工作....... returntrue; }
相信我们很多人都写过类似上面的代码。我们可以看到,上面的代码中包含了很多错误检查和资源清理的代码。过多的错误代码检查和资源清理工作会使得代码难以阅读,同时也难以编写、修改和维护。
现在让我们来通过使用SEH机制改进上面的代码:
bool fun(char* fileName) { HANDLEhFile=INVALID_HANDLE_VALUE; HANDLEhFileMapping=NULL; char*p=NULL; __try { hFile=CreateFile(....); if(hFile==INVALID_HANDLE_VALUE) __leave; hFileMapping=CreateFileMapping(...); if(hFile==NULL) __leave; p=MapViewOfFile(..); if(p==NULL) __leave; //其他代码。 } __finally { if(hFile!=INVALID_HANDLE_VALUE) CloseHandle(hFile); if(hFileMapping) CloseHandle(hFileMapping); } returntrue; }
从上面的代码我们可以看到代码简洁多了。清理工作放在最后执行,且能够保证能得到执行,代码看起来简洁而有序,
struct dst_entry *dst = skb_dst(skb);
struct neighbour *neigh;
int rc = 0;
if (!dst || !(neigh = dst->neighbour)) 异常退出
goto discard;
__skb_pull(skb, skb_network_offset(skb));
if (!neigh_event_send(neigh, skb)) { 判断邻居项是否有可用状态,如果可用,则把数据包发送出去
int err;
struct net_device *dev = neigh->dev;
if (dev->header_ops->cache && !dst->hh) {
write_lock_bh(&neigh->lock);
if (!dst->hh)
neigh_hh_init(neigh, dst, dst->ops->protocol);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
write_unlock_bh(&neigh->lock);
} else {
read_lock_bh(&neigh->lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
read_unlock_bh(&neigh->lock);
}
if (err >= 0)
rc = neigh->ops->queue_xmit(skb);
else
goto out_kfree_skb;
}
out:
return rc;
discard:
NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
dst, dst ? dst->neighbour : NULL);
out_kfree_skb:
rc = -EINVAL;
kfree_skb(skb);
goto out;
}
if (dev->header_ops->cache && !dst->hh) { 如果hh为空 邻居项的高速缓存
write_lock_bh(&neigh->lock);
if (!dst->hh)
neigh_hh_init(neigh, dst, dst->ops->protocol); 进行hh的初始化
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len); 根据HH的信息构造二层头
write_unlock_bh(&neigh->lock);
} else { hh不为空时,直接根据HH的信息构造二层头
read_lock_bh(&neigh->lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
read_unlock_bh(&neigh->lock);
}
if (err >= 0) 加头成功直接输出
rc = neigh->ops->queue_xmit(skb);
else
goto out_kfree_skb;
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_resolve_output,
.connected_output = neigh_resolve_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
__be16 protocol)
{
struct hh_cache *hh;
struct net_device *dev = dst->dev;
for (hh = n->hh; hh; hh = hh->hh_next) 从路由的协议下手找
if (hh->hh_type == protocol)
break;
if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { 找不到则申请
seqlock_init(&hh->hh_lock);
hh->hh_type = protocol; 协议类型赋值
atomic_set(&hh->hh_refcnt, 0);
hh->hh_next = NULL;
if (dev->header_ops->cache(n, hh)) { 该函数为eth_header_cache
kfree(hh);
hh = NUL