Module: PhusionPassenger::NativeSupport

Defined in:
ext/ruby/passenger_native_support.c

Defined Under Namespace

Classes: FileSystemWatcher

Constant Summary collapse

UNIX_PATH_MAX =

The maximum length of a Unix socket path, including terminating null.

INT2NUM(sizeof(addr.sun_path))
SSIZE_MAX =

The maximum size of the data that may be passed to #writev.

LL2NUM(SSIZE_MAX)

Class Method Summary collapse

Class Method Details

.detach_process(pid) ⇒ Object



417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File 'ext/ruby/passenger_native_support.c', line 417

static VALUE
detach_process(VALUE self, VALUE pid) {
	pthread_t thr;
	pthread_attr_t attr;
	size_t stack_size = 96 * 1024;
	
	unsigned long min_stack_size;
	int stack_min_size_defined;
	int round_stack_size;
	
	#ifdef PTHREAD_STACK_MIN
		// PTHREAD_STACK_MIN may not be a constant macro so we need
		// to evaluate it dynamically.
		min_stack_size = PTHREAD_STACK_MIN;
		stack_min_size_defined = 1;
	#else
		// Assume minimum stack size is 128 KB.
		min_stack_size = 128 * 1024;
		stack_min_size_defined = 0;
	#endif
	if (stack_size != 0 && stack_size < min_stack_size) {
		stack_size = min_stack_size;
		round_stack_size = !stack_min_size_defined;
	} else {
		round_stack_size = 1;
	}
	
	if (round_stack_size) {
		// Round stack size up to page boundary.
		long page_size;
		#if defined(_SC_PAGESIZE)
			page_size = sysconf(_SC_PAGESIZE);
		#elif defined(_SC_PAGE_SIZE)
			page_size = sysconf(_SC_PAGE_SIZE);
		#elif defined(PAGESIZE)
			page_size = sysconf(PAGESIZE);
		#elif defined(PAGE_SIZE)
			page_size = sysconf(PAGE_SIZE);
		#else
			page_size = getpagesize();
		#endif
		if (stack_size % page_size != 0) {
			stack_size = stack_size - (stack_size % page_size) + page_size;
		}
	}
	
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, 1);
	pthread_attr_setstacksize(&attr, stack_size);
	pthread_create(&thr, &attr, detach_process_main, (void *) NUM2LONG(pid));
	pthread_attr_destroy(&attr);
	return Qnil;
}

.disable_stdio_bufferingObject

Disables any kind of buffering on the C stdout and stderr variables, so that fprintf() on stdout and stderr have immediate effect.



98
99
100
101
102
103
# File 'ext/ruby/passenger_native_support.c', line 98

static VALUE
disable_stdio_buffering(VALUE self) {
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);
	return Qnil;
}

.freeze_processObject

Freeze the current process forever. On Ruby 1.9 this never unlocks the GIL. Useful for testing purposes.



475
476
477
478
479
480
481
# File 'ext/ruby/passenger_native_support.c', line 475

static VALUE
freeze_process(VALUE self) {
	while (1) {
		usleep(60 * 1000000);
	}
	return Qnil;
}

.process_timesObject



393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'ext/ruby/passenger_native_support.c', line 393

static VALUE
process_times(VALUE self) {
	struct rusage usage;
	unsigned long long utime, stime;
	
	if (getrusage(RUSAGE_SELF, &usage) == -1) {
		rb_sys_fail("getrusage()");
	}
	
	utime = (unsigned long long) usage.ru_utime.tv_sec * 1000000 + usage.ru_utime.tv_usec;
	stime = (unsigned long long) usage.ru_stime.tv_sec * 1000000 + usage.ru_stime.tv_usec;
	return rb_struct_new(S_ProcessTimes, rb_ull2inum(utime), rb_ull2inum(stime));
}

.split_by_null_into_hash(data) ⇒ Object

Split the given string into an hash. Keys and values are obtained by splitting the string using the null character as the delimitor.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'ext/ruby/passenger_native_support.c', line 109

static VALUE
split_by_null_into_hash(VALUE self, VALUE data) {
	const char *cdata   = RSTRING_PTR(data);
	unsigned long len   = RSTRING_LEN(data);
	const char *begin   = cdata;
	const char *current = cdata;
	const char *end     = cdata + len;
	VALUE result, key, value;
	
	result = rb_hash_new();
	while (current < end) {
		if (*current == '\0') {
			key   = rb_str_substr(data, begin - cdata, current - begin);
			begin = current = current + 1;
			while (current < end) {
				if (*current == '\0') {
					value = rb_str_substr(data, begin - cdata, current - begin);;
					begin = current = current + 1;
					rb_hash_aset(result, key, value);
					break;
				} else {
					current++;
				}
			}
		} else {
			current++;
		}
	}
	return result;
}

.writev(fd, components) ⇒ Object

Writes all of the strings in the components array into the given file descriptor using the writev() system call. Unlike IO#write, this method does not require one to concatenate all those strings into a single buffer in order to send the data in a single system call. Thus, #writev is a great way to perform zero-copy I/O.

Unlike the raw writev() system call, this method ensures that all given data is written before returning, by performing multiple writev() calls and whatever else is necessary.

writev(@socket.fileno, ["hello ", "world", "\n"])


363
364
365
366
# File 'ext/ruby/passenger_native_support.c', line 363

static VALUE
f_writev(VALUE self, VALUE fd, VALUE components) {
	return f_generic_writev(fd, &components, 1);
}

.writev2(fd, components1, components2) ⇒ Object

Like #writev, but accepts two arrays. The data is written in the given order.

writev2(@socket.fileno, ["hello ", "world", "\n"], ["another ", "message\n"])


373
374
375
376
377
# File 'ext/ruby/passenger_native_support.c', line 373

static VALUE
f_writev2(VALUE self, VALUE fd, VALUE components1, VALUE components2) {
	VALUE array_of_components[2] = { components1, components2 };
	return f_generic_writev(fd, array_of_components, 2);
}

.writev3(fd, components1, components2, components3) ⇒ Object

Like #writev, but accepts three arrays. The data is written in the given order.

writev3(@socket.fileno,
  ["hello ", "world", "\n"],
  ["another ", "message\n"],
  ["yet ", "another ", "one", "\n"])


387
388
389
390
391
# File 'ext/ruby/passenger_native_support.c', line 387

static VALUE
f_writev3(VALUE self, VALUE fd, VALUE components1, VALUE components2, VALUE components3) {
	VALUE array_of_components[3] = { components1, components2, components3 };
	return f_generic_writev(fd, array_of_components, 3);
}