+
+T_HELPER_DECL(check_frozen, "Check frozen state", T_META_ASROOT(true)) {
+ int kern_ret;
+ dispatch_source_t ds_signal;
+ __block int is_frozen;
+ /* Set the process to freezable */
+ kern_ret = memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_FREEZABLE, getpid(), 1, NULL, 0);
+ T_QUIET; T_ASSERT_POSIX_SUCCESS(kern_ret, "set process is freezable");
+ /* Signal to our parent that we can be frozen */
+ if (kill(getppid(), SIGUSR1) != 0) {
+ T_LOG("Unable to signal to parent process!");
+ exit(SIGNAL_TO_PARENT_FAILED);
+ }
+
+ /* We should not be frozen yet. */
+ is_frozen = memorystatus_control(MEMORYSTATUS_CMD_GET_PROCESS_IS_FROZEN, getpid(), 0, NULL, 0);
+ if (is_frozen == -1) {
+ T_LOG("memorystatus_control error: %s", strerror(errno));
+ exit(MEMORYSTATUS_CONTROL_ERROR);
+ }
+ if (is_frozen) {
+ exit(FROZEN_BIT_SET);
+ }
+
+
+ sig_t sig_ret = signal(SIGUSR1, SIG_IGN);
+ T_QUIET; T_WITH_ERRNO; T_ASSERT_NE(sig_ret, SIG_ERR, "signal(SIGUSR1, SIG_IGN)");
+ ds_signal = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dispatch_get_main_queue());
+ if (ds_signal == NULL) {
+ exit(DISPATCH_SOURCE_CREATE_FAILED);
+ }
+
+ dispatch_source_set_event_handler(ds_signal, ^{
+ /* We should now be frozen. */
+ is_frozen = memorystatus_control(MEMORYSTATUS_CMD_GET_PROCESS_IS_FROZEN, getpid(), 0, NULL, 0);
+ if (is_frozen == -1) {
+ T_LOG("memorystatus_control error: %s", strerror(errno));
+ exit(MEMORYSTATUS_CONTROL_ERROR);
+ }
+ if (!is_frozen) {
+ exit(FROZEN_BIT_NOT_SET);
+ }
+ exit(SUCCESS);
+ });
+ dispatch_activate(ds_signal);
+
+ dispatch_main();
+}
+
+T_DECL(memorystatus_get_process_is_frozen, "MEMORYSTATUS_CMD_GET_PROCESS_IS_FROZEN returns correct state") {
+ skip_if_freezer_is_disabled();
+
+ test_after_background_helper_launches(true, "check_frozen", ^{
+ int ret;
+ /* Freeze the child, resume it, and signal it to check its state */
+ move_to_idle_band(child_pid);
+ ret = pid_suspend(child_pid);
+ T_ASSERT_POSIX_SUCCESS(ret, "child suspended");
+ freeze_process(child_pid);
+ ret = pid_resume(child_pid);
+ T_ASSERT_POSIX_SUCCESS(ret, "child resumed after freeze");
+
+ kill(child_pid, SIGUSR1);
+ /* The child will checks its own frozen state & exit. */
+ });
+}