改变进程名称有很好的理由。Java软件应该更改进程名称,因为在运行不同的Java工具时,我想知道哪个Java进程是哪个工具。
Chromium做到了:http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm。
Node.js使用相同的代码来实现Process.title = 'newtitle'
:https://github.com/joyent/node/blob/master/src/platform_darwin_proctitle.cc
注意:如果有人使用su
切换到其他未登录用户,则此方法会失败:https://github.com/joyent/node/issues/1727
这里是源代码的全部内容。顺便说一句,有人告诉我它也适用于Mac OS X Lion,并且在使用su
时也会失败。
void SetProcessName(CFStringRef process_name) {
if (!process_name || CFStringGetLength(process_name) == 0) {
NOTREACHED() << "SetProcessName given bad name.";
return;
}
if (![NSThread isMainThread]) {
NOTREACHED() << "Should only set process name from main thread.";
return;
}
typedef CFTypeRef PrivateLSASN;
typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
CFStringRef,
CFStringRef,
CFDictionaryRef*);
static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
NULL;
static LSSetApplicationInformationItemType
ls_set_application_information_item_func = NULL;
static CFStringRef ls_display_name_key = NULL;
static bool did_symbol_lookup = false;
if (!did_symbol_lookup) {
did_symbol_lookup = true;
CFBundleRef launch_services_bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
if (!launch_services_bundle) {
LOG(ERROR) << "Failed to look up LaunchServices bundle";
return;
}
ls_get_current_application_asn_func =
reinterpret_cast<LSGetCurrentApplicationASNType>(
CFBundleGetFunctionPointerForName(
launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
if (!ls_get_current_application_asn_func)
LOG(ERROR) << "Could not find _LSGetCurrentApplicationASN";
ls_set_application_information_item_func =
reinterpret_cast<LSSetApplicationInformationItemType>(
CFBundleGetFunctionPointerForName(
launch_services_bundle,
CFSTR("_LSSetApplicationInformationItem")));
if (!ls_set_application_information_item_func)
LOG(ERROR) << "Could not find _LSSetApplicationInformationItem";
CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>(
CFBundleGetDataPointerForName(launch_services_bundle,
CFSTR("_kLSDisplayNameKey")));
ls_display_name_key = key_pointer ? *key_pointer : NULL;
if (!ls_display_name_key)
LOG(ERROR) << "Could not find _kLSDisplayNameKey";
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
}
if (!ls_get_current_application_asn_func ||
!ls_set_application_information_item_func ||
!ls_display_name_key) {
return;
}
PrivateLSASN asn = ls_get_current_application_asn_func();
const int magic_session_constant = -2;
OSErr err =
ls_set_application_information_item_func(magic_session_constant, asn,
ls_display_name_key,
process_name,
NULL );
LOG_IF(ERROR, err) << "Call to set process name failed, err " << err;
}
编辑: 这是一个复杂而混乱的问题。
在OS X上没有setproctitle(3)。一个人必须写入argv数组(丑陋并且有点危险,因为可能会用虚假的东西覆盖一些环境变量)。如果正确地完成,它可以很好地工作。
此外,苹果公司有ActivityMonitor应用程序,类似于Windows下的任务管理器。上面的代码操作ActivityMonitor,但这种操作似乎并不被苹果公司鼓励(因此使用了未经文件化的函数)。
重要提示:ps和ActivityMonitor不显示相同的信息。
还要注意:如果您没有GUI,则无法使用ActivityMonitor。如果您通过ssh登录到远程Apple盒子,并且没有任何人通过GUI登录,则可能会发生这种情况。可悲的是,苹果公司存在一个错误,在我看来。只是查询是否有GUI会向stderr发送一个烦人的警告消息。
总结: 如果您需要更改ActivityMonitor,请使用上面的代码。如果您遇到无GUI的情况并且不喜欢stderr上的警告,请在调用SetProcessName
时将stderr暂时重定向到/dev/null。如果您需要更改ps信息,请写入argv。
argv [0]
和setproctitle()
)。 - Marco Masser