error LNK2038: mismatch detected for ‘_ITERATOR_DEBUG_LEVEL’: value ‘2’ doesn’t match value ‘0’ in xxx.obj

Finally, I think I find a workaround to your linking failure. Here is what under the
hood, please be patient to read through. 🙂

 

First of all to answer your question, MC3 never explicitly sets
_HAS_ITERATOR_DEBUGGING either in release or debug version, so it’s always by
default. And we do use STL thoughout the code – containers, iterators,
functors.

 

I reviewed your linking error message again:

xxxd.lib(MLStaticUtil.obj)
: error LNK2038:
mismatch detected for ‘_ITERATOR_DEBUG_LEVEL’: value ‘2’ doesn’t match value
‘0’ in xx.obj

 

Basically, it has nothing to do with _HAS_ITERATOR_DEBUGGING directly, but instead a new preprocessor marco – _ITERATOR_DEBUG_LEVEL, which is new added in VS2010.
According to MSDN: The new _ITERATOR_DEBUG_LEVEL macro invokes debugging
support for iterators. Use this macro instead of the older _SECURE_SCL and _HAS_ITERATOR_DEBUGGING macros. So, if Softimage does want to disable checked iterator, you have to upgrade your build settings with using _ITERATOR_DEBUG_LEVEL !

 

After
revewing the source code of STL (in YVALS.H), you have to find the following:

 

#ifdef
__cplusplus

#ifndef _ALLOW_MSC_VER_MISMATCH

#pragma detect_mismatch(“_MSC_VER”, “1600”)

#endif /* _ALLOW_MSC_VER_MISMATCH */

#ifndef
_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH

#if _ITERATOR_DEBUG_LEVEL == 0

#pragma
detect_mismatch(“_ITERATOR_DEBUG_LEVEL”, “0”)

#elif _ITERATOR_DEBUG_LEVEL == 1

#pragma
detect_mismatch(“_ITERATOR_DEBUG_LEVEL”, “1”)

#elif _ITERATOR_DEBUG_LEVEL == 2

#pragma detect_mismatch(“_ITERATOR_DEBUG_LEVEL”,
“2”)

#else

#error Unrecognized _ITERATOR_DEBUG_LEVEL
value.

#endif

#endif /* _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH */

#endif /* __cplusplus */

 

Please
notice the highlighted lines, again, detect_mismatch – new feature introduced in VS2010, where error LNK2038 is originated from. I can confirm this referring to MSDN: http://msdn.microsoft.com/en-us/library/ee956429.aspx

“When you link the project, the linker throws a LNK2038 error if the project contains
two objects that have the same name but each has a different value. Use this pragma to prevent inconsistent object files from linking.”

 

So the impact of above code is that if several compile units (object files),
containing different value for _ITERATOR_DEBUG_LEVEL, linking will failed. By
default _ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH is not defined, and I even cannot find this under MSDN, so it is obvious that VS2010 is trying to forbid the case
that several compile units with different _ITERATOR_DEBUG_LEVEL. Generally,
it’s a good design, as it effectively avoid the incorrect use of MS CRT library.

 

You may also ask me: I did not set _ITERATOR_DEBUG_LEVEL at all, why the link
complains about it? OK, here is the answer: as you set _HAS_ITERATOR_DEBUGGING=0, which causes _ITERATOR_DEBUG_LEVEL=0 implicitly. Again, code from YVALS.H.

 

#if
_HAS_ITERATOR_DEBUGGING

#define _ITERATOR_DEBUG_LEVEL 2

#elif _SECURE_SCL

#define _ITERATOR_DEBUG_LEVEL 1

#else

#define _ITERATOR_DEBUG_LEVEL 0

#endif

 

So in xxxd.lib, _ITERATOR_DEBUG_LEVEL is by default 2, while your cer.obj is
complied with _ITERATOR_DEBUG_LEVEL 0, the value is different cross these two
compile unit, thus linker stops work by throwing the error message – error LNK2038.

 

As a summary, the way to disable checked iterator in debug build
for Softimage without disabling/rebuilding MC3 debug version is just to set
_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
so as to turn of mismatch checking.
The
only concern is that you lose the support to ensure the correct use of
dependency libraries.

linux-0.12 div64的实现分析

首先要说明的是,书中注释的一个错误,真是害人不浅,严重影响后续代码的阅读。

AT&T汇编:sub A, B,应该是B – A,结果放入B中。所以try_sub (a, b) 就是b– a,结果放入b中。这样再来看div64的实现:

static void div64(int * a, int * b, int * c)

{

int tmp[4];

int i;

unsigned int mask = 0;

c += 4;

for (i = 0 ; i<64 ; i++) {

if (!(mask >>= 1)) {

c–;

mask = 0x80000000;

}

tmp[0] = a[0]; tmp[1] = a[1];

tmp[2] = a[2]; tmp[3] = a[3];

if (try_sub(b,tmp)) {

*c |= mask;

a[0] = tmp[0]; a[1] = tmp[1];

a[2] = tmp[2]; a[3] = tmp[3];

}

shift_right(b);

}

}

本质上就是一个手工竖式除法运算。这里的a和b都是指向16字节内存的指针(在模拟程序中,我们只考虑64位的精度,所以足够了)。数据在a和b中都是向最高位对齐的(参见fdiv的实现),也就是说a[3],a[2]中存放了被除数,b[3],b[2]中是除数。例如,被除数111011和除数1011,在内存中的摆放形式(这里是逻辑形式,不考虑物理倒序):

  1. 11101100 … 000000000 – 128位
  2. 10110000 … 000000000 – 128 位

这样按照传统的手工计算方法10110000 … 000000000 ) 11101100 … 000000000,就是#1 – #2,结果值作为#1,然后#2右移移位,对齐上方竖式,继续#1 – #2。直到不够减为止。够减与不够减就是通过if (try_sub (b, tmp)) 来判断。商存放在c所指内存中,也是向最高位对齐的。商的计算很巧妙,够减则在对应位上置1。

总的来说,二进制的除法,因为只有0和1,所以整个过程相对于十进制简单了许多,只要相减移位即可。

 

Win Autobuck again

Austin is a great example of an ACRD developer taking the lead on an important, urgent and complex issue and successfully driving it to resolution.  He demonstrated great initiative and problem solving skills by proactively digging in and identifying the issue in the Microsoft file, and then posting questions on the Microsoft forum.  He developed a good working relationship with a couple of Microsoft experts who identified the problem and provided an updated files.  His commitment to driving to speedy resolution enabled product teams to address the .Net 4.0 CERs during the endgame and resolve stability issues during the beta phase, prior to release.  Awesome job, Austin!       – Kieran McKeogh

It’s my honour.  ^_^ Oh, I will start a serial of posts on the use of ICorDebug v4. Stay tuned!

Austin.D

Process group, session, controlling terminal…

要搞清楚linux/Unix上,进程、进程组、会话、控制终端、前台进程组、后台进程组神马的,看下面的几篇文章就可以搞清楚了。

另,在linux 0.12内核中,有以下几点需要注意:

  • fg_console,前台控制台,其实根本就不是字面意义上的前台,它仅仅只是当前正在使用的虚拟控制终端而已(无非就是不同的显示内存区段);
  • linux 0.12中没有实现tcgetpgrp和tcsetpgrp,所以前台进程组和后台进程组之间的切换没法完成;
  • 所谓的控制终端,可以是虚拟控制台tty,可以使串口终端(通过猫连接),甚至是mpty/spty。只要会话首进程可以打开,平且用于管理/控制作业就OK了。

Austin.D

Summary on char dev driver in Linux0.12

控制台终端

当用户通过键盘输入时,键盘中断程序会将接收到的扫描码进行转义(有些是显示字符,可以直接显示在屏幕上;有些是控制字符,控制序列,转义序列什么的),写入read_q队列中。然后调用tty_do_interrupt来进一步调用copy_to_cooked,将read_q中的内容读出。这里分两部走:1)根据规范模式进行基于字符行的转换操作,并写入secondary队列中,供上层程序读取使用。如tty_read,会把secondary中的内容copy给用户指定的缓冲区中。2)如果需要回显(echo),则将转换操作结果写入write_q中,并调用con_write输出到屏幕上。屏幕输出无非就是把字符数据(包括字符属性)写到对应的显示内存位置上去。

另一种情况就是用户的程序经过系统调用,间接调用到tty_write,将要输出的数据写入write_q,然后tty_write进一步调用con_write输出到当前终端的显示屏幕上。

串行终端

当串行终端有数据要被接收时,会产生串行设备的中断。linux0.12的串行中断处理程序会判断中断来源。如果是接收数据中断,那么就读取RBR接收缓存寄存器,将接收到的字符写入read_q中。之后的过程类似于控制台终端的情况,只是调用的子程序会有些不同。同样,中断处理程序会调用tty_do_interrupt来进一步调用copy_to_cooked,将read_q中的内容读出。同样分两步走。1)规范模式转换结果,依旧是放入secondary队列中,供上层的tty_read获取数据。2)如果要回显,则写回write_q中,并通过调用rs_write来将数据发送回串行终端。这里要注意的是,rs_write并不是真正干发送操作的地方,它仅仅是打开了发送保持寄存器,以允许空时中断。这里很绕口,其实就是这个寄存器,当它是空的时候会发生中断。所以平时他所对应的中断源是被禁止掉的。而rs_write的作用就是在发送之前打开这个中端。这样,串行中断处理程序会被调用,这次的中断源变成了“设置发送保持寄存器中断允许标志”,然后调用write_char子程序,将write_q中的数据送往发送保持寄存器,从而发送出去。

发送串行数据和控制台一样,通过tty_write,将要发送的数据写入write_q,然后tty_write进一步调用write_char来发送。

伪终端(主/从配对)

伪终端是最有意思的一个,也是实现上最简单的一个,所以书上没有列出它的源代码,但是自己看看就能够懂了。伪终端派什么用?其实就是用来进程间通信的。我们经常会需要在自己的程序中调用一个shell命令,然后读入shell命令的处理结果,然后进行分析。要注意的是,伪终端永远都是配对使用的!对一个伪终端进行读操作,就是接收它所配对的那个伪终端写入的数据。从实现上来看,当前伪终端tty_read读操作,肯定是读自己的secondary队列,它的数据来自于自己的read_q。自己read_q的内容就是配对的那个伪终端写入的数据,也就是它write_q中的数据。这样看来,就是一个数据的copy操作而已,从从伪终端中write_q,copy到自己的read_q中,然后调用copy_to_cooked来规范模式处理。linux0.12就是这么做的。

几个Sleep/Wakeup点

在tty_write中写入数据之前,如果write_q已经满了,那么当前调用tty_write的进程就会睡眠等待,这里是可中断的等待。在write_char中和pty.c中会唤醒等待在write_q上的进程。奇怪的是con_write中没有。难道是bug?这个我还没调试过。

tty_read只从secondary中获取提供给上层程序的数据。如果secondary为空,则睡眠等待。在copy_to_cooked会唤醒。

对于read_q,我只看到两处对于进程唤醒的操作:tty_read中和中断处理程序的put_queue中。但是从来没看到过有进程为sleep在它上面,