ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [운영체제] 시스템 호출 (System Call)
    운영체제 2023. 8. 9. 20:56

    Overview


    전에 운영체제의 핵심이 되는 커널에 대해 알아봤습니다.

    2023.08.07 - [운영체제] - [운영체제] 커널(Kernel)

     

    [운영체제] 커널(Kernel)

    Overview 커널(Kernel)은 컴퓨터 운영체제의 핵심이 되는 컴퓨터 프로그램(Software)입니다. 커널은 시스템의 모든 것을 완전히 제어합니다. OS의 다른 부분 및 응용 프로그램 수행에 필요한 여러 가지

    hogumachu.tistory.com

    커널 이미지

    위의 이미지처럼 프로그램은 직접적인 연결이 아닌 커널을 통한 간접적인 연결이 되었습니다.

    프로그램이 직접적으로 접근할 수 없다는 것 입니다.

     

    프로그램이 직접적인 연결이 가능하다면?


    하나의 프로그램이 하나의 리소스에 접근

    만약 하나의 프로그램이 파일(리소스)에 직접적인 접근을 하면 문제가 없을 수도 있습니다 (있을 수도 있음..!)

     

     

    여러 프로그램이 하나의 리소스에 접근

    여러 프로그램이 하나의 파일에 직접적으로 접근하면 문제가 일어날 것입니다.

    파일을 작성하고 있는데 이미 제거되었던가 등..

    만약 중요한 리소스를 이런 식으로 접근하게 된다면 훨씬 큰 문제가 일어날 것입니다.

     

     

    커널을 통한 리소스 접근

    따라서 자원 보호를 위해 프로그램이 직접 접근을 방지하고 커널을 통해 접근합니다.

     

    시스템 호출


    커널은 부팅 과정에서 전체 메모리 리소스 중 일정 부분을 점유하여 동작하고 인터럽트 등 모든 하드웨어에 접근이 가능합니다.

    그러나 응용 프로그램은 위의 이미지처럼 여러 상황에서 커널에 의존을 해야 합니다.

    응용 프로그램에서 커널의 기능을 사용하는 방법이 바로 시스템 호출 (System Call, 시스템 콜) 입니다.

     

     사용자 모드와 커널 모드

    사용자 모드커널의 기능을 사용할 수 없는 모드입니다. (커널 모드는 반대)

    일반적인 응용 프로그램은 기본적으로 사용자 모드로 실행이 됩니다.

    따라서 시스템 콜을 통해 사용자 모드에서 커널 모드로 변경을 하여 커널의 기능을 사용합니다.

     

    시스템 콜

     

    Swift에서의 시스템 콜


    📌 Caution: 혼자 라이브러리를 뜯어보며 확인한 정보라 정확하지 않습니다. 감안해서 봐주세요.

     

     

    사실 FileManager의 내부를 보고 싶었는데 찾다가 포기했습니다. 😭

    https://github.com/apple/swift-system

     

    GitHub - apple/swift-system: Low-level system calls and types for Swift

    Low-level system calls and types for Swift. Contribute to apple/swift-system development by creating an account on GitHub.

    github.com

    그러던 와중 Swift 시스템 콜에 대한 것이 있어 사용해봤습니다.

    import Foundation
    import SystemPackage
    
    let text = "hello, hogumachu"
    let path: FilePath = "/tmp/log"
    let fileDescriptor = try FileDescriptor.open(
        path, .writeOnly, // 올바른 권한
        options: [.append, .create],
        permissions: .ownerReadWrite
    )
    
    try fileDescriptor.closeAfter {
        try fileDescriptor.writeAll(text.utf8)
    }

    파일을 Open하여 Write를 하는 기능입니다.

    올바른 권한으로 하면 예상대로 잘 동작하고 저장합니다.

    let fileDescriptor = try FileDescriptor.open(
        path, .readOnly, // .writeOnly -> .readOnly
        options: [.append, .create],
        permissions: .ownerReadWrite
    )

    권한을 readOnly로 변경하게 되면 아주 친절하게 에러 문구가 나옵니다.

    Swift/ErrorType.swift:200: Fatal error: Error raised at top level: Bad file descriptor
    2023-08-09 19:22:08.118429+0900 SystemCall[93558:8136241] Swift/ErrorType.swift:200: Fatal error: Error raised at top level: Bad file descriptor

    SystemCall 이라는 로그가 남겨진 것을 보아 뭔가 문제가 생긴 것은 맞는 것 같습니다.

    Bad file descriptor 라는 문구가 인상적이네요. 그래서 찾아봤습니다.

    // 출처: https://github.com/apple/swift-system/blob/main/Sources/System/Errno.swift#L161
    
     /// Bad file descriptor.
      ///
      /// A file descriptor argument was out of range,
      /// referred to no open file,
      /// or a read (write) request was made to a file
      /// that was only open for writing (reading).
      ///
      /// The corresponding C error is `EBADF`.
      @_alwaysEmitIntoClient
      public static var badFileDescriptor: Errno { Errno(_EBADF) }
    
      @_alwaysEmitIntoClient
      @available(*, unavailable, renamed: "badFileDescriptor")
      public static var EBADF: Errno { badFileDescriptor }

    상황 설명이 잘 되어있습니다.

    EBADF 에 대한 것도 찾아봅시다.

    // 출처: https://github.com/apple/swift-system/blob/main/Sources/System/Internals/WindowsSyscallAdapters.swift#L106
    
    @inline(__always)
    internal func pwrite(
      _ fd: Int32, _ buf: UnsafeRawPointer!, _ nbyte: Int, _ offset: off_t
    ) -> Int {
      let handle: intptr_t = _get_osfhandle(fd)
      if handle == /* INVALID_HANDLE_VALUE */ -1 { return Int(EBADF) }
    
      // NOTE: this is a non-owning handle, do *not* call CloseHandle on it
      let hFile: HANDLE = HANDLE(bitPattern: handle)!
    
      var ovlOverlapped: OVERLAPPED = OVERLAPPED()
      ovlOverlapped.OffsetHigh = DWORD(UInt32(offset >> 32) & 0xffffffff)
      ovlOverlapped.Offset = DWORD(UInt32(offset >> 0) & 0xffffffff)
    
      var nNumberOfBytesWritten: DWORD = 0
      if !WriteFile(hFile, buf, DWORD(nbyte), &nNumberOfBytesWritten,
                    &ovlOverlapped) {
        let _ = GetLastError()
        // TODO(compnerd) map windows error to errno
        return Int(-1)
      }
      return Int(nNumberOfBytesWritten)
    }

    참고해야할 점은 위의 코드는 windowOS에서의 SystemCall 어댑터입니다. (macOS와 다르니까 뭔가 핸들러가 필요한 것 같습니다)

    fd라는 값을 통해 handle을 불러옵니다.

    fd라는 값은 FileDescriptor의 rawValue(CInt)로 플래그처럼 이용하는 것 같습니다 (뇌피셜)

    // 출처: https://github.com/apple/swift-system/blob/main/Sources/System/Internals/Syscalls.swift
    
    internal func system_open(
      _ path: UnsafePointer<CInterop.PlatformChar>, _ oflag: Int32
    ) -> CInt {
    #if ENABLE_MOCKING
      if mockingEnabled {
        return _mock(path: path, oflag)
      }
    #endif
      return open(path, oflag)
    }
    
    internal func system_open(
      _ path: UnsafePointer<CInterop.PlatformChar>,
      _ oflag: Int32, _ mode: CInterop.Mode
    ) -> CInt {
    #if ENABLE_MOCKING
      if mockingEnabled {
        return _mock(path: path, oflag, mode)
      }
    #endif
      return open(path, oflag, mode)
    }
    
    // write
    internal func system_write(
      _ fd: Int32, _ buf: UnsafeRawPointer?, _ nbyte: Int
    ) -> Int {
    #if ENABLE_MOCKING
      if mockingEnabled { return _mockInt(fd, buf, nbyte) }
    #endif
      return write(fd, buf, nbyte)
    }

    Syscalls.swift 파일을 확인해보면... 네 이런 식으로 호출이 되는군요.

    위의 open과 write에 접근해본 결과 커널 시간에 알아봤던 XNU 기반의 다윈이 등장했습니다.

     

    더 알아보기는 나중으로 미루고 궁금하신 분을 위해 링크 첨부합니다.

    https://github.com/apple/darwin-xnu/tree/main/libsyscall

     

    마무리


    간단하게 시스템 콜에 대해 알아봤는데 Swift System에서는 Swif System 라이브러리에서 에러에 대한 핸들링을 어느정도 하는 모습을 볼 수 있었습니다. (https://github.com/apple/swift-system/blob/main/Sources/System/Errno.swift)

     

    처음에는 파일을 읽고 쓰는 것에 대해 크게 생각하지 않았지만 이제는 시스템 콜이라는 것을 보면 커널 기능을 사용하는 것이구나 생각이 들 것 같아 아주 좋았습니다.

     

    결국 많은 정보를 알기 위해 엄청난 로우 레벨로 가야 하는데... 어느정도가 적절한 것인지 잘 모르겠습니다.

     

    읽어주셔서 감사합니다.

     

    참고


    https://ko.wikipedia.org/wiki/%EC%8B%9C%EC%8A%A4%ED%85%9C_%ED%98%B8%EC%B6%9C

    https://namu.wiki/w/%EC%8B%9C%EC%8A%A4%ED%85%9C%20%EC%BD%9C

    https://github.com/apple/swift-system/tree/main

    https://gist.github.com/Azoy/a39cd31285d6d2e5c5e0d370675c290d

    '운영체제' 카테고리의 다른 글

    [운영체제] 스레드(Thread)  (0) 2023.08.11
    [운영체제] 프로세스(Process)  (0) 2023.08.10
    [운영체제] 커널(Kernel)  (0) 2023.08.07
Designed by Tistory.