由于linux argv和environ环境变量内存地址连续,同时argv[0]代表进程name,所以就可以尽可能的用连续的内存空间(起始地址argv[0])来设置进程name
test case如下:
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#define LOGDBG(fmt, args...) do {\
printf("[%s:%d]%s "fmt"\n", __FILE__, __LINE__, __FUNCTION__, ##args);\
}while(0);
extern char **environ;
int main(int argc, char** argv)
{
uint32_t i = 0;
uint32_t env_size = 0;
for (; environ[i];i++)
{
env_size += strlen(environ[i])+1;//\0 char
LOGDBG("environ[i]=%s", environ[i]);
}
LOGDBG("env_size:%u", env_size);
char* env = (char*) malloc(env_size);
char* temp = env;
for(i = 0; environ[i]; i++)
{
snprintf(temp, strlen(environ[i])+1, "%s", environ[i]);
environ[i] = temp;
temp += strlen(environ[i])+1;
}
char* last = environ[i]-1;
argv[1] = NULL;
snprintf(argv[0], last - argv[0], "%s", "set title");
for (i=0; environ[i];i++)
{
LOGDBG("environ[i]=%s", environ[i]);
}
sleep(10);
return 0;
}
testcase 根据的是nginx设置进程为master or worker process的做法,nginx的code 如下:
extern char **environ;
static char *ngx_os_argv_last;
ngx_int_t
ngx_init_setproctitle(ngx_log_t *log)
{
u_char *p;
size_t size;
ngx_uint_t i;
size = 0;
//首先计算出environ需要的内存空间
for (i = 0; environ[i]; i++) {
size += ngx_strlen(environ[i]) + 1;
}
//为environ分配内存空间
p = ngx_alloc(size, log);
if (p == NULL) {
return NGX_ERROR;
}
ngx_os_argv_last = ngx_os_argv[0];
//check连续性
for (i = 0; ngx_os_argv[i]; i++) {
if (ngx_os_argv_last == ngx_os_argv[i]) {
ngx_os_argv_last = ngx_os_argv[i] + ngx_strlen(ngx_os_argv[i]) + 1;
}
}
//copy environ到新分配的内存
for (i = 0; environ[i]; i++) {
if (ngx_os_argv_last == environ[i]) {
size = ngx_strlen(environ[i]) + 1;
ngx_os_argv_last = environ[i] + size;
ngx_cpystrn(p, (u_char *) environ[i], size);
environ[i] = (char *) p;
p += size;
}
}
ngx_os_argv_last--;
return NGX_OK;
}
void
ngx_setproctitle(char *title)
{
u_char *p;
#if (NGX_SOLARIS)
ngx_int_t i;
size_t size;
#endif
//先把argv数组的第二个节点置为空
ngx_os_argv[1] = NULL;
//copy
p = ngx_cpystrn((u_char *) ngx_os_argv[0], (u_char *) "nginx: ",
ngx_os_argv_last - ngx_os_argv[0]);
p = ngx_cpystrn(p, (u_char *) title, ngx_os_argv_last - (char *) p);
#if (NGX_SOLARIS)
size = 0;
for (i = 0; i < ngx_argc; i++) {
size += ngx_strlen(ngx_argv[i]) + 1;
}
if (size > (size_t) ((char *) p - ngx_os_argv[0])) {
/*
* ngx_setproctitle() is too rare operation so we use
* the non-optimized copies
*/
p = ngx_cpystrn(p, (u_char *) " (", ngx_os_argv_last - (char *) p);
for (i = 0; i < ngx_argc; i++) {
p = ngx_cpystrn(p, (u_char *) ngx_argv[i],
ngx_os_argv_last - (char *) p);
p = ngx_cpystrn(p, (u_char *) " ", ngx_os_argv_last - (char *) p);
}
if (*(p - 1) == ' ') {
*(p - 1) = ')';
}
}
#endif
if (ngx_os_argv_last - (char *) p) {
ngx_memset(p, NGX_SETPROCTITLE_PAD, ngx_os_argv_last - (char *) p);
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
"setproctitle: \"%s\"", ngx_os_argv[0]);
}
#endif /* NGX_SETPROCTITLE_USES_ENV */
也是先copy environ到新的地址空间,用连续的内存空间来设置进程title