[linux] 배쉬 : 무한 수면 (무한 차단)

startx내 X를 평가하는 데 사용 합니다 .xinitrc. 내 .xinitrc에서을 사용하여 창 관리자를 시작 /usr/bin/mywm합니다. 이제 WM을 죽이면 (다른 WM을 테스트하기 위해) .xinitrc스크립트가 EOF에 도달 했기 때문에 X도 종료됩니다 . 그래서 나는 이것을 내 끝에 추가했다 .xinitrc:

while true; do sleep 10000; done

이렇게하면 WM을 죽이면 X가 종료되지 않습니다. 이제 내 질문 : 루핑 수면 대신 무한 수면을 어떻게 할 수 있습니까? 스크립트를 정지시키는 것과 같은 명령이 있습니까?

친애하는



답변

sleep infinity 고양이 학대없이 제안하고 작동하는 것을 정확하게 수행합니다.


답변

tail 차단하지 않습니다

항상 그렇듯이 : 모든 것에 대해 짧고 이해하기 쉽고 따르기 쉽고 완전히 잘못된 대답이 있습니다. 여기이 tail -f /dev/null범주에 속합니다.)

당신이 그것을 보시면 strace tail -f /dev/null이 솔루션은 차단되지 않습니다! sleepLinux와 같은 inotify시스템 과 같은 귀중한 리소스를 사용하기 때문에 문제 의 솔루션 보다 훨씬 나쁩니다 . 또한 루프 를 /dev/null만들기 위해 쓰는 다른 프로세스 tail. (Ubuntu64 16.10에서는 이미 사용량이 많은 시스템에서 초당 10 회의 syscall이 추가됩니다.)

문제는 차단 명령이었습니다

불행히도, 그런 것은 없습니다 ..

읽는다 : 나는 이것을 쉘로 직접 보관할 방법을 모른다.

모든 sleep infinity신호는 심지어 일부 신호에 의해 중단 될 수 있습니다. 따라서 예외적으로 반환되지 않는지 확인하려면 이미 수행 한 것처럼 루프에서 실행해야합니다 sleep. (Linux의 경우) /bin/sleep24 일에 한도를 정했다는 점을 명심하십시오 ( strace sleep infinity따라서 살펴보십시오 ).

while :; do sleep 2073600; done

(내가 sleep24 일보다 높은 값을 위해 내부적으로 루프를 믿지만 이것은 차단하지 않고 매우 느리게 반복됩니다.이 루프를 외부로 옮기지 않는 이유는 무엇입니까?)

.. 그러나 당신은 이름 없는와 꽤 가까이 올 수 있습니다 fifo

프로세스에 신호가 전송되지 않는 한 실제로 차단되는 것을 만들 수 있습니다. 다음 bash 4과 같이 2 개의 PID와 1을 사용합니다 fifo.

bash -c 'coproc { exec >&-; read; }; eval exec "${COPROC[0]}<&-"; wait'

원하는 strace경우 이것이 실제로 차단 되는지 확인할 수 있습니다.

strace -ff bash -c '..see above..'

이것이 어떻게 구성 되었는가

read입력 데이터가없는 경우 차단합니다 (다른 답변 참조). 그러나 tty(일명. stdin)은 일반적으로 사용자가 로그 아웃 할 때 닫히기 때문에 좋은 소스가 아닙니다. 또한에서 일부 입력을 훔칠 수 있습니다 tty. 좋지 않아.

read차단 하려면 fifo아무것도 반환하지 않는 것과 같은 것을 기다릴 필요가 있습니다. 에서 bash 4정확히 같은 우리를 제공 할 수있는 명령이 있습니다 fifo: coproc. 차단 read( 대기자)을 기다리면 coproc완료됩니다. 슬프게도 이것은 두 개의 PID와 a를 열어 두어야합니다 fifo.

명명 된 변형 fifo

named를 사용하지 않으면 fifo다음과 같이 할 수 있습니다.

mkfifo "$HOME/.pause.fifo" 2>/dev/null; read <"$HOME/.pause.fifo"

읽기에 루프를 사용하지 않는 것은 약간 느슨하지만, fifo원하는만큼 자주 재사용 하고 reads를 사용하여 터미널을 사용할 수 있습니다 touch "$HOME/.pause.fifo"(하나 이상의 읽기 대기가있는 경우 모든 것이 한 번에 종료 됨).

또는 Linux pause()syscall을 사용하십시오.

무한 차단을 위해 리눅스 커널 호출이 있는데, pause()우리가 원하는 것을한다 : 신호가 도착할 때까지 영원히 기다린다. 그러나 이것에 대한 사용자 공간 프로그램은 아직 없습니다.

그러한 프로그램을 만드는 것은 쉽습니다. 여기라는 매우 작은 리눅스 프로그램을 만들 수있는 조각이다 pause무기한 (요구 일시 정지 diet, gcc등)

printf '#include <unistd.h>\nint main(){for(;;)pause();}' > pause.c;
diet -Os cc pause.c -o pause;
strip -s pause;
ls -al pause

python

직접 컴파일하고 싶지는 않지만 python설치 한 경우 Linux에서이를 사용할 수 있습니다.

python -c 'while 1: import ctypes; ctypes.CDLL(None).pause()'

(참고 : exec python -c ...현재 셸을 교체하는 데 사용 하면 PID 하나가 해제됩니다. 일부 IO 리디렉션을 통해 솔루션을 개선하여 사용하지 않는 FD를 해제 할 수도 있습니다. 이는 사용자에게 달려 있습니다.)

작동 방식 (제 생각) : ctypes.CDLL(None)표준 C 라이브러리를로드하고 pause()추가 루프 내 에서 함수를 실행합니다 . C 버전보다 효율적이지 않지만 작동합니다.

당신을위한 나의 추천 :

반복 수면을 유지하십시오. 이해하기 쉽고 휴대 성이 뛰어나며 대부분의 시간을 차단합니다.


답변

어쩌면 이것이 못생긴 것처럼 보이지만 실행을 cat계속하고 입력을 영원히 기다리게 하지 않는 이유는 무엇입니까?


답변

TL; DR : sleep infinity실제로 허용 된 최대 시간을 잠들게합니다.

왜 이것이 어디에도 문서화되어 있지 않은지 궁금 해서 GNU coreutils 에서 소스 를 읽으려고 노력했으며 대략 다음과 같이 실행됩니다.

  1. strtod‘무한대’를 배정도로 변환하려면 첫 번째 인수에서 C stdlib에서 사용하십시오 . 따라서 IEEE 754 배정도를 가정하면 64 비트 양의 무한대 값이 seconds변수에 저장됩니다 .
  2. 호출은 xnanosleep(seconds)( gnulib에서 발견 )이 차례를 발동에 dtotimespec(seconds)( 도 gnulib의 ) 변환하는 방법 doublestruct timespec.
  3. struct timespec정수 부분 (초)과 소수 부분 (나노초)의 숫자 쌍입니다. 양의 무한대 를 정수 로 순전히 변환 하면 정의되지 않은 동작이 발생하고 (C 표준의 §6.3.1.4 참조) 대신로 절단됩니다 TYPE_MAXIMUM (time_t).
  4. 실제 값은 TYPE_MAXIMUM (time_t)표준에 설정되어 있지 않습니다 ( sizeof(time_t)그렇지 않더라도). 예를 들어 최근 Linux 커널에서 x86-64를 선택하겠습니다.

이것은 TIME_T_MAXLinux 커널에 있으며 다음과 같이 ( time.h)로 정의 됩니다.

(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)

참고 time_t__kernel_time_ttime_t입니다 long; LP64 데이터 모델이 사용되므로 sizeof(long)8 (64 비트)도 사용됩니다.

결과 : TIME_T_MAX = 9223372036854775807.

sleep infinite, 실제 절전 시간은 9223372036854775807 초 (10 ^ 11 년)입니다. 그리고 32 비트 리눅스 시스템의 경우 ( sizeof(long)4 (32 비트)) : 2147483647 초 (68 년; 2038 년 문제 도 참조하십시오 ).


편집 : 분명히 nanoseconds호출 된 함수는 직접 syscall이 아니라 OS 종속 래퍼 ( gnulib에 정의되어 있음 )입니다.

그 결과로 추가 단계가 있습니다 : 일부 시스템 HAVE_BUG_BIG_NANOSLEEPtrue수면 24 일립니다 다음 루프에서했다. 이것은 일부 (또는 모두?) Linux 배포판의 경우입니다. configure- time 테스트가 성공한 경우 ( source ) 이 랩퍼를 사용할 수 없습니다 .

특히, 24 * 24 * 60 * 60 = 2073600 seconds(99999999 나노초 플러스); 그러나 지정된 총 절전 시간을 준수하기 위해 루프에서 호출됩니다. 따라서 이전 결론은 유효합니다.


결론적 으로 , 결과적인 실제 시간 경과가 휴대용이 아닌 경우에도 결과적인 수면 시간 은 무한하지만 모든 실제적인 목적을 위해 충분히 높을 수 없다. OS와 아키텍처에 따라 다릅니다.

원래 질문에 대답하기에, 이것은 분명히 충분하지만 어떤 이유로 ( 매우 자원이 제한된 시스템) 쓸모없는 여분의 카운트 다운 타이머를 피하고 싶다면 가장 적합한 대안은 cat다른 답변에 설명 된 방법 을 사용하는 것입니다 .


답변

sleep infinity가장 우아해 보이지만 때로는 어떤 이유로 작동하지 않습니다. 이 경우, 다른 차단 명령과 같은 시도 할 수 있습니다 cat, read, tail -f /dev/null, grep a


답변

SIGSTOP 을 자신 에게 보내는 것은 어떻습니까?

SIGCONT가 수신 될 때까지 프로세스를 일시 정지해야합니다. 당신의 경우에는 : 결코.

kill -STOP "$$";
# grace time for signal delivery
sleep 60;


답변

sleep infinity문서화되지 않았지만 작동 하는지 설명하겠습니다 . jp48의 답변 도 유용합니다.

가장 중요한 것 : inf또는 infinity(대소 문자를 구분하지 않음) 을 지정 하면 구현에서 허용하는 가장 긴 시간 동안 (예 : HUGE_VAL및 값이 더 작은) 휴면 상태가 될 수 있습니다 TYPE_MAXIMUM(time_t).

이제 세부 사항을 파헤쳐 보자. sleep명령 소스 코드는 coreutils / src / sleep.c 에서 읽을 수 있습니다 . 기본적으로 함수는 다음을 수행합니다.

double s; //seconds
xstrtod (argv[i], &p, &s, cl_strtod); //`p` is not essential (just used for error check).
xnanosleep (s);

이해 xstrtod (argv[i], &p, &s, cl_strtod)

xstrtod()

gnulib / lib / xstrtod.c 에 따르면 , 호출은 변환 함수를 사용하여 xstrtod()문자열 argv[i]을 부동 소수점 값 *s으로 변환하여 저장합니다 cl_strtod().

cl_strtod()

에서 볼 수 있듯이 로 coreutils / lib 디렉토리 / CL-strtod.c , cl_strtod()사용, 부동 소수점 값에 문자열로 변환합니다 strtod().

strtod()

에 따르면 man 3 strtod, strtod()유형의 값에 문자열로 변환합니다 double. 맨 페이지 말한다

(문자열의 초기 부분)의 예상 형식은 … 또는 (iii) 무한대 또는 …

무한대는

무한대는 대소 문자를 무시하고 “INF”또는 “INFINITY”입니다.

문서가 알려 주지만

올바른 값으로 오버플로가 발생하면 더하기 또는 빼기 HUGE_VAL( HUGE_VALF, HUGE_VALL)가 반환됩니다.

무한대가 어떻게 취급되는지는 명확하지 않다. 소스 코드 gnulib / lib / strtod.c를 보자 . 우리가 읽고 싶은 것은

else if (c_tolower (*s) == 'i'
         && c_tolower (s[1]) == 'n'
         && c_tolower (s[2]) == 'f')
  {
    s += 3;
    if (c_tolower (*s) == 'i'
        && c_tolower (s[1]) == 'n'
        && c_tolower (s[2]) == 'i'
        && c_tolower (s[3]) == 't'
        && c_tolower (s[4]) == 'y')
      s += 5;
    num = HUGE_VAL;
    errno = saved_errno;
  }

따라서, INFINFINITY(대소 문자 구별)는 다음과 같이 간주된다 HUGE_VAL.

HUGE_VAL 가족

N1570 을 C 표준으로 사용합시다 . HUGE_VAL, HUGE_VALFHUGE_VALL매크로에 정의되어 §7.12-3

매크로
    HUGE_VAL
는 양의 상수 상수로 확장되며 반드시 부동 소수점으로 표현할 필요는 없습니다. 매크로
    HUGE_VALF
    HUGE_VALL
는 각각 부동 및 긴 이중 아날로그입니다 HUGE_VAL.

HUGE_VAL, HUGE_VALFHUGE_VALL인피니티를 지원하는 구현에서 긍정적 인 인피니티 일 수 있습니다.

§7.12.1-5

부동 결과가 오버 플로우 및 기본 반올림이 적용되는 경우,이 함수는 매크로의 값을 반환 HUGE_VAL, HUGE_VALF또는 HUGE_VALL반환 형식에 따라

이해 xnanosleep (s)

이제 우리는의 모든 본질을 이해합니다 xstrtod(). 위의 설명에서, xnanosleep(s)우리가 실제로 본 것은 실제로 의미 하는 것은 명백합니다 xnanosleep(HUGE_VALL).

xnanosleep()

소스 코드 gnulib / lib / xnanosleep.c에 따르면 xnanosleep(s)본질적으로 다음을 수행합니다.

struct timespec ts_sleep = dtotimespec (s);
nanosleep (&ts_sleep, NULL);

dtotimespec()

이 함수는 type 인수를 type double객체 로 변환합니다 struct timespec. 매우 간단하므로 소스 코드 gnulib / lib / dtotimespec.c를 인용 하겠습니다 . 모든 의견은 저에 의해 추가됩니다.

struct timespec
dtotimespec (double sec)
{
  if (! (TYPE_MINIMUM (time_t) < sec)) //underflow case
    return make_timespec (TYPE_MINIMUM (time_t), 0);
  else if (! (sec < 1.0 + TYPE_MAXIMUM (time_t))) //overflow case
    return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1);
  else //normal case (looks complex but does nothing technical)
    {
      time_t s = sec;
      double frac = TIMESPEC_HZ * (sec - s);
      long ns = frac;
      ns += ns < frac;
      s += ns / TIMESPEC_HZ;
      ns %= TIMESPEC_HZ;

      if (ns < 0)
        {
          s--;
          ns += TIMESPEC_HZ;
        }

      return make_timespec (s, ns);
    }
}

이후 time_t일체형으로 정의된다 (§7.27.1-3 참조), 우리가 유형의 최대 값이 가정 자연 time_t보다 작다 HUGE_VAL(유형 double우리가 오버 플로우하는 경우 입력 수단). (실제로이 절차는 본질적으로 동일하기 때문에이 가정은 필요하지 않습니다.)

make_timespec()

우리가 올라 가야하는 마지막 벽은 make_timespec()입니다. 운 좋게도 소스 코드 gnulib / lib / timespec.h 를 인용하면 충분합니다.

_GL_TIMESPEC_INLINE struct timespec
make_timespec (time_t s, long int ns)
{
  struct timespec r;
  r.tv_sec = s;
  r.tv_nsec = ns;
  return r;
}