NDK(jni) JAVA与C互传数组对象

最近在搞NDK底层一些功能的开发,被一个问题折腾了3天,起初一直以为是C这边的位运算出了问题,查到最后才发现是数组传递出了问题,一开始我是这样写的:

void Java_com_xxx_test1(JNIEnv* env, jobject thiz, jint* javaArray, jint array_size) {
other_function((int *)javaArray, (int)array_size);
}

真正正确的写法应该是这样:

void Java_com_xxx_test1(JNIEnv* env, jobject thiz, jintArray* javaArray) {
// For C
jint* pJint = (*env)->GetByteArrayElements(env, javaArray, 0);
jsize array_size = (*env)->GetArrayLength(env, javaArray);
// For C++
// jint* pJint = env->GetByteArrayElements(javaArray, 0);
// jsize array_size = env->GetArrayLength(javaArray);
other_function((int *)pJint, array_size);
}

理论上讲这个问题应该是很容易发现的,但我为什么纠结了这么久呢,因为在之前我的另一段类似的代码中是工作正常的,像这样:

void Java_com_xxx_test2(JNIEnv* env, jobject thiz, jint* javaArray, jint array_size) {
int a[10]; // 假设 array_size 一定会小于10
int i;
for (int = 0; i < array_size; i++)
{
a[i] = (int)javaArray[i];
}
}

所以我一直认为第一种写法是正确的,害死人啊。

C回传数组给JAVA是这样做的:

jintArray Java_com_xxx_test3(JNIEnv* env, jobject thiz) {
int a = {1, 2, 3, 4};
jbyteArray result;
result = (*env)->NewByteArray(env, 4);
(*env)->SetIntArrayRegion(env, result, 0, 4, a);
// For C++
// result = env->NewByteArray(4);
// env->setIntArrayRegion(result, 0, 4, a);
return result
}

Gentoo 安装 charlock_holmes

最近折腾gitlab + gitolite,安装到charlock_holmes一步出现一堆 undefined reference 错误,官方网站也有这么一个issue

解决办法:修改/usr/lib64/ruby/1.9.1/x86_64-linux/rbconfig.rb,删除CONFIG[“LDFLAGS”] 一行最后的“-Wl,–no-undefined”,具体原因未知。

NDK note: the mangling of ‘va_list’ has changed in GCC 4.4

最近搞NDK,一切还算顺利,只是每次ndk-build都会提示:

In file included from jni/fskmodule.cpp:7:0:
/xxxx/usr/include/jni.h:592:13: note: the mangling of 'va_list' has changed in GCC 4.4

解决办法,修改 Android.mk,加一行:

LOCAL_CFLAGS = -Wno-psabi

KVM使用原生CPU

默认情况下 CentOS 6 安装虚拟机后的CPU是:QEMU Virtual CPU,一般使用是没有问题的,只是性能低下,PHP一个10万次循环的脚本居然需要执行50多秒,而母系统执行只需2秒多,差距有点儿太大。

# virsh edit vm_name
<domain type='kvm'>
......
<qemu:commandline>
<qemu:arg value='-cpu'/>
<qemu:arg value='host'/>
</qemu:commandline>
</domain>

一般建议使用 virsh edit 编辑虚拟机配置文件,避免文件被破坏。

libvirt与qemu 几个常用命令

克隆一个虚拟机:

virt-clone -o formdomain -n todomain -f /path/filename.img

转换镜像格式:

qemu-img convert -O qcow2 filename.img filename.qcow2

支持的格式:raw、qcow、qcow2、vmdk、vdi

查看一个镜像的信息:

qcmu-img info filename.img

调整镜像大小

qemu-img resize filename.img +|-size

CentOS 6 安装配置KVM小记

作为一名半调子系统管理员,XEN那dom0,domU还要编译内核,这简直要了我的亲命,KVM作为一个CentOS 6开始唯一内置支持的虚拟化,安装配置简单,很适合我。

安装:

KVM需要CPU支持vmx(Intel)或svm(AMD)。

$ cat /proc/cpuinfo | egrep 'vmx|svm'
flags: fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36
clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm
3dnowext 3dnow constant_tsc rep_good nonstop_tsc extd_apicid pni monitor
cx16 popcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a
misalignsse 3dnowprefetch osvw ibs skinit wdt npt lbrv svm_lock nrip_save
flags: fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36
clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm
3dnowext 3dnow constant_tsc rep_good nonstop_tsc extd_apicid pni monitor
cx16 popcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a
misalignsse 3dnowprefetch osvw ibs skinit wdt npt lbrv svm_lock nrip_save

安装KVM组件

# yum groupinstall Virtualization
# yum groupinstall "Virtualization Platform"

重启后检查是否安装成功,若使用Intel CPU会显示 kvm_intel。

# lsmod | grep kvm
kvm_amd                37434  4 
kvm                   292815  1 kvm_amd

OK,就这么简单,KVM安装完成。

周边工具:

virt-manger与virt-viewer是基于X Window的图形化管理工具,优点呢就是操作简单、鼠标点点,坏处自然就是要装一堆图形组件,对于服务器来说这些东西有些太多余。
服务器上最好用的当然是命令行工具

yum install libvirt-client python-virtinst

libvirt-client 提供了 virsh,主要功能为:启动、重启、停止等管理功能。
python-virtinst 提供了 virt-install 安装工具。

安装虚拟机

#&nbsp;virt-install \
--name gentoo6 \
--ram 512 \
--vcpus=1 \
--disk path=/var/vps/gentoo6.img,size=4 \
--network network:default \
--os-variant=generic26 \
--accelerate \
--cdrom /var/vps/install-amd64-minimal-20111201.iso \
--vnc \
--vncport=5911 \
--vnclisten=0.0.0.0

–name 指定虚拟机名称,virsh操作指定虚拟机时所需要的参数,不可以重复。
–ram 分配内存大小,安装完成后可以用 virsh 调整。
–vcpus 分配CPU核心数,最大与实体机CPU核心数相同,安装完成后也可以用 virsh 调整。
–disk 指定虚拟机镜像, size 指定分配大小单位为G。
–network 网络类型,此处用的是默认,一般用的应该是 bridge 桥接,这个下次再说。
–os-variant 指定操作系统类型,此处使用的是标准Linux 2.6,其他的可以通过 man virt-install 详细查看。
–accelerate 呃,加速,具体什么原理还不太清楚。
–cdrom 指定安装镜像所在。
–vnc 启用VNC远程管理,一般安装系统都要启用。
–vncport 指定 VNC 监控端口,默认端口为 5900。
–vnclisten 指定 VNC 绑定IP,默认绑定127.0.0.1,这里将其改为 0.0.0.0 以便可以通过外部连接。
执行后如果没有安装 virt-viewer 或没有 X Window 系统可能会提示 virt-viewer 启动失败,不过没关系,使用 VNC Viewer 或者 MAC 下使用Chicken of the VNC连接到实体机,端口使用上面指定的就可以操作安装过程。另外需要注意的是,某些系统安装盘有等待输入时间,超过时间会自动使用硬盘启动,所以VNC连接一定要快,否则就需要 virsh destroy 然后 virsh start 再启动,因为系统尚未安装成功,此时的 virsh reboot 执行是无效的。

virsh 常用命令

virsh list 列出当前虚拟机列表,貌似不包括未启动的。
virsh start domain-name 启动指定虚拟机。
virsh shutdown domain-name 停止指定虚拟机,执行此命令后 virsh list 里将不出现。
virsh reboot domain-name 重新启动指定虚拟机,这个命令貌似必须系统安装完成后才有效。
virsh autostart domain-name 指定虚拟机开机自动启动,需要 libvirtd 服务默认启动。
还有更多,一时也没全搞明白,全写出来估计可以写本手册了。

其他

虚拟机配置存储在 /etc/libvirt/qemu 目录,配置文件为XML格式。
自动启动的虚拟机在 /etc/libvirt/qemu/autostart 目录。

simplejson处理不严谨JSON一例

一个标准、严谨的JSON应该如下:

{"title": "\u6587\u7ae0\u6807\u9898\n\u6362\u884c"}

但是在某些情况下,特别是跨语言情况下,JSON可能是这个样子:

{"title": "文章标题
换行"}

这种情况下直接使用 simplejson.loads(json) 有可能报如下错误:

Traceback (most recent call last):
  File "testjson.py", line 24, in <module>
    print simplejson.loads(json)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/
site-packages/PIL/__init__.py", line 384, in loads

  File "build/bdist.macosx-10.5-i386/egg/simplejson/decoder.py", line 402, 
in decode
  File "build/bdist.macosx-10.5-i386/egg/simplejson/decoder.py", line 418, 
in raw_decode
simplejson.decoder.JSONDecodeError: Invalid control character at: line 1 
column 15 (char 15)

simplejson.loads() 有一个手册上没有提及的参数“strict”,这其实是 JSONDecoder 的一个构造参数,即不严格检查JSON语法。

因此,兼容非标准格式的方法即:

simplejson.loads(json, strict=False)

svn: Can’t move ‘.svn/tmp/entries’ to ‘.svn/entries’: Operation not permitted

SVN 总是在 Mac OS 下出现这句错误提示,这个问题一般在与 Windows 共用一个目录,并在 Windows 下进行过 svn up 操作后,老外对此给出了解决方法,但是最近这个站点在国内经常打不开,在此记一笔为自己备记。

进入项目目录执行:

chflags -R nouchg .

老外给的方法是:

chflags -R nouchg *

但是有时会依然会无法解决问题,两种方法都试试吧。