Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#closes 243] Procdump debug & Refactor console struct. #286

Closed
wants to merge 30 commits into from
Closed

[#closes 243] Procdump debug & Refactor console struct. #286

wants to merge 30 commits into from

Conversation

coolofficials
Copy link
Collaborator

@coolofficials coolofficials commented Nov 21, 2020

구현 상 아직 논의가 필요한 부분이 있지만, 리뷰 부탁드립니다.
#276 의 논의가 너무 길어지고 #281 이후 resolve 하기 힘든 conflict가 많이 생겨서 새롭게 PR을 작성했습니다.

  1. Processsystem::dump 출력 시 null character recognizing 문제 해결.
  • while loop을 이용한 해결방법이 현재 발견한 최선입니다.
  • magic number 16을 MAXPROCNAME으로 정의했습니다.
  1. 지난 주 팀 미팅에서 논의한대로 Console / Printer / Uart의 Ownership을 정돈했습니다.
  • 다음과 같이 struct Console을 변경했습니다.
struct Console {
    terminal: Sleepablelock<Terminal>,
    printer: Spinlock<Printer>,
    uart: Uart,
}
  • 기존의 struct Consolestruct Terminal이라는 임시 이름으로 변경했습니다.
  • 역할이 다르기 때문에 struct Printerstruct Terminal(구 Console)을 분리해야합니다.
    • Terminal은 user program의 input output logging, Printerprintln! 매크로를 위해 존재합니다.
    • xv6에서 pr.lockcons.lock은 항상 따로 잡힙니다.
  • Uart가 하나만 존재하게 하는 ownership 정리가 필요합니다.

kernel-rs/src/console.rs Outdated Show resolved Hide resolved
kernel-rs/src/console.rs Show resolved Hide resolved
kernel-rs/src/console.rs Outdated Show resolved Hide resolved
@coolofficials coolofficials marked this pull request as draft November 21, 2020 19:10
match cin {
// Print process list.
m if m == ctrl('P') => {
m if m == ctrl('P') => unsafe {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 block만 unsafe 하다고 판단했습니다. 나머지 block은 Console::putc->Uart::putc_sync->UartCtrlRegs::read로 safety가 reduce 됩니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 block은 왜 unsafe한가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProcessSystem::dump->p.info.get_mut_unchecked()'를 통해 ProcInfo에 접근합니다.
dump의 unsafe block을 특정지어서 safety를 reduce 해봤습니다.
safety에 대해서 미팅 때 여쭤보겠습니다.

};
}

unsafe fn write(&mut self, src: UVAddr, n: i32) -> i32 {
unsafe fn write(&self, src: UVAddr, n: i32) -> i32 {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

write/read/intr 함수들의 소유를 struct Terminal로 옮기는 편이 좋을까요?
그 경우 intrputc를 사용하고 있어서 kernel()을 부르게 됩니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 수정한다면, writeuart를 사용하고 있어서 kernel()을 불러야 할 것 같습니다.
  • 아래 Printer::Write과 같은 정책을 사용하는 것이 좋다고 생각합니다. (둘 다 각자 소유 / 다 Console이 소유)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anemoneflower 소유권 표현 상으로는 kernel()을 부르더라도 Terminal으로 이동하는 것이 좋다는 말씀이시죠?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

소유권만 보면 TerminalPrinter가 각각 소유하는 것이 맞는 것 같습니다. 그런데, 코드 구조 상으로는 Console이 다 소유하는 것이 더 깔끔해 보입니다.. PrinterTerminalConsole에서만 사용되기 때문에 Console의 소유로 남겨도 괜찮을 것 같은데, 다른 분들의 의견은 어떠신가요?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 ownership을 중점적으로 생각해 TerminalPrinter가 각각 소유하면 좋겠습니다! 추가로 아래의 현재 kaist-cp/rv6의 구현처럼, write/read/intr을 실행하기 전 consoleread/consolewrite/consoleintr에서 lock()을 실행하면 소유권을 더욱 명확히 나타낼 수 있다고 생각합니다!

unsafe fn consolewrite(src: UVAddr, n: i32) -> i32 {
let mut console = kernel().console.lock();
console.write(src, n)
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeehoonkang 교수님, 현재 논점이 global function kernel()의 사용을 지양하는 것과 ownership을 조금 더 세분화하는 것 중에 선택하는 것입니다. 교수님의 의견이 궁금합니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

같은 질문을 드리고자 하는데 왜 &self로 해도 안전한가요? 여러 쓰레드가 동시 접근해도 문제가 안생기나요?

Copy link
Collaborator Author

@coolofficials coolofficials Nov 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. terminal에 lock을 잡고 있습니다.
  2. Uart::putc의 경우 uart.tx_lock으로 보호됩니다. 여러 쓰레드가 동시에 접근하면 어떤 문제가 생길 수 있나요?

@coolofficials coolofficials marked this pull request as ready for review November 21, 2020 19:53
Copy link
Member

@jeehoonkang jeehoonkang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다.. 다만 제가 console, terminal, printer, uart 사이의 관계에 대해 잘 파악하기 어렵습니다. 혹시 주석으로 얘네들이 뭐 하는건지 남겨주시면 감사하겠습니다.

아울러 원래 xv6의 의도를 100% 반영하는지, 아니면 좀 바뀐 부분이 있는지 궁금합니다.

kernel-rs/src/uart.rs Show resolved Hide resolved
@coolofficials
Copy link
Collaborator Author

coolofficials commented Nov 22, 2020

@jeehoonkang
말씀하신 부분 Commentation 완료했습니다. 별도의 issue로 분리해야하는 discussion들 address 했습니다. Discussion들(especially #286 (comment) #286 (comment) #286 (comment)) 확인하시고 의견 주시거나 resolve 해주시면 감사하겠습니다.

"아울러 원래 xv6의 의도를 100% 반영하는지, 아니면 좀 바뀐 부분이 있는지 궁금합니다."

결론적으로 말하자면 의도를 100% 반영한다고 생각합니다.
xv6가 의도한대로 Uart의 uniqueness, PrinterConsole(현 Terminal)의 분리를 확실히 표현해주는 추상화라고 생각합니다.

결국 세 struct가 전부 User와 interact 하는 Console device와 관련된 interface라는 점에서도 의미를 더욱 명확히 표현하고 있다고 생각합니다. xv6의 조금은 정돈되지 못한 표현들이 rust의 ownership을 통해 정리가 된 것 같습니다.

Copy link
Collaborator

@kimjungwow kimjungwow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다! 저는 ownership 위주로 고민해봤습니다 👍👍

kernel-rs/src/console.rs Outdated Show resolved Hide resolved
};
}

unsafe fn write(&mut self, src: UVAddr, n: i32) -> i32 {
unsafe fn write(&self, src: UVAddr, n: i32) -> i32 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 ownership을 중점적으로 생각해 TerminalPrinter가 각각 소유하면 좋겠습니다! 추가로 아래의 현재 kaist-cp/rv6의 구현처럼, write/read/intr을 실행하기 전 consoleread/consolewrite/consoleintr에서 lock()을 실행하면 소유권을 더욱 명확히 나타낼 수 있다고 생각합니다!

unsafe fn consolewrite(src: UVAddr, n: i32) -> i32 {
let mut console = kernel().console.lock();
console.write(src, n)
}

kernel-rs/src/console.rs Outdated Show resolved Hide resolved
kernel-rs/src/console.rs Show resolved Hide resolved
kernel-rs/src/proc.rs Outdated Show resolved Hide resolved
kernel-rs/src/proc.rs Show resolved Hide resolved
@coolofficials
Copy link
Collaborator Author

coolofficials commented Nov 23, 2020

@jeehoonkang ping 리뷰 요청드립니다.
소유권 표현의 문제로 global 함수 kernel()의 사용이 많아졌습니다.
소유권의 표현이 kernel()을 지양하는 것보다 우선적인 것으로 합의가 되어 그렇게 진행했습니다.

@coolofficials
Copy link
Collaborator Author

coolofficials commented Nov 23, 2020

@efenniht #186 (comment) 이 부분에 대한 refactoring도 진행된 것 같은데, 확인 부탁드립니다.

struct Console이 모듈이라기보다는 Console device의 추상화가 되었기 때문에 interrupt를 받는다고 생각해도 괜찮을까요?

Copy link
Member

@jeehoonkang jeehoonkang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일반적으로 이 PR이 달성하고자하는 바를 잘 모르겠습니다.

pub fn uartintr(&self) {
self.uart.intr()
}

/// Send one character to the uart.
pub fn putc(&mut self, c: i32) {
pub fn putc(&self, c: i32) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여전히 이게 &self인게 이해가 잘 안갑니다. 여러 thread가 동시에 putc를 부르면 어떻게 되나요?

Copy link
Collaborator Author

@coolofficials coolofficials Nov 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생각해봤는데, 명확히 어떤 문제가 생기는지 reasoning이 잘 안됩니다. 면담 때 이런 경우에 어떻게 reasoning 할 수 있는지 가르침을 청해도 될까요?

Uart::putc_sync는 interrupt disable을 통해 synchronization을 handling 중입니다.

};
}

unsafe fn write(&mut self, src: UVAddr, n: i32) -> i32 {
unsafe fn write(&self, src: UVAddr, n: i32) -> i32 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

같은 질문을 드리고자 하는데 왜 &self로 해도 안전한가요? 여러 쓰레드가 동시 접근해도 문제가 안생기나요?


unsafe fn read(&self, dst: UVAddr, n: i32) -> i32 {
let mut terminal = self.terminal.lock();
terminal.read(dst, n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 terminal로 바로 보내는 함수들이 많다면, console이라는 abstraction이 틀린 걸지도 모르겠습니다. 어떻게 보시나요?

Copy link
Collaborator Author

@coolofficials coolofficials Nov 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이전 커밋 상태로 role back 하겠습니다. 그쪽 디자인이 옳은 것 같아서요.

  • console이라는 abstraction을 만든 이유가 uart의 ownership을 분명히하고자 하는 것인데, 이런식으로 terminal을 부르는게 그 의미를 담지 못하는 것 같습니다.
  • b2c26c4 에서는 console의 uart를 이용하는 방식이었는데, 해당 디자인에서는 console abstraction의 존재 의미를 잘 살리고 있다고 생각하여 role back 하겠습니다.
  • 혹시 맥락이 잘못되었다면 말씀해주세요.

for i in 0..n {
let mut c = [0 as u8];
if VAddr::copyin(&mut c, UVAddr::new(src.into_usize() + (i as usize))).is_err() {
return i;
}
self.uart.putc(c[0] as i32);
kernel().console.uart.putc(c[0] as i32);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 이건 잘못된 디자인이라고 생각합니다. uart의 소유권에 대한 명확한 정립이 먼저 필요한 것 같아요.

Copy link
Collaborator Author

@coolofficials coolofficials Nov 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생각해봤는데, 이러한 디자인을 사용하는 것이 잘못된 것이 맞는 것 같습니다. 이번 PR의 목적 중 하나가 uart의 소유권을 console이 가지도록 하는 것인데, 이렇게 사용하면 의미가 퇴색되는 것 같습니다.

b2c26c4 에서처럼 uart의 소유권을 console이 지니는 것을 분명히 하여 console의 존재 의미를 살리는 방식으로 role back 하겠습니다.

match cin {
// Print process list.
m if m == ctrl('P') => {
m if m == ctrl('P') => unsafe {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 block은 왜 unsafe한가요?

Copy link
Collaborator Author

@coolofficials coolofficials left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

putc의 multithread 접근에 대해서 조금 더 생각해보겠습니다.

};
}

unsafe fn write(&mut self, src: UVAddr, n: i32) -> i32 {
unsafe fn write(&self, src: UVAddr, n: i32) -> i32 {
Copy link
Collaborator Author

@coolofficials coolofficials Nov 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. terminal에 lock을 잡고 있습니다.
  2. Uart::putc의 경우 uart.tx_lock으로 보호됩니다. 여러 쓰레드가 동시에 접근하면 어떤 문제가 생길 수 있나요?

match cin {
// Print process list.
m if m == ctrl('P') => {
m if m == ctrl('P') => unsafe {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProcessSystem::dump->p.info.get_mut_unchecked()'를 통해 ProcInfo에 접근합니다.
dump의 unsafe block을 특정지어서 safety를 reduce 해봤습니다.
safety에 대해서 미팅 때 여쭤보겠습니다.


unsafe fn read(&self, dst: UVAddr, n: i32) -> i32 {
let mut terminal = self.terminal.lock();
terminal.read(dst, n)
Copy link
Collaborator Author

@coolofficials coolofficials Nov 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이전 커밋 상태로 role back 하겠습니다. 그쪽 디자인이 옳은 것 같아서요.

  • console이라는 abstraction을 만든 이유가 uart의 ownership을 분명히하고자 하는 것인데, 이런식으로 terminal을 부르는게 그 의미를 담지 못하는 것 같습니다.
  • b2c26c4 에서는 console의 uart를 이용하는 방식이었는데, 해당 디자인에서는 console abstraction의 존재 의미를 잘 살리고 있다고 생각하여 role back 하겠습니다.
  • 혹시 맥락이 잘못되었다면 말씀해주세요.

for i in 0..n {
let mut c = [0 as u8];
if VAddr::copyin(&mut c, UVAddr::new(src.into_usize() + (i as usize))).is_err() {
return i;
}
self.uart.putc(c[0] as i32);
kernel().console.uart.putc(c[0] as i32);
Copy link
Collaborator Author

@coolofficials coolofficials Nov 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생각해봤는데, 이러한 디자인을 사용하는 것이 잘못된 것이 맞는 것 같습니다. 이번 PR의 목적 중 하나가 uart의 소유권을 console이 가지도록 하는 것인데, 이렇게 사용하면 의미가 퇴색되는 것 같습니다.

b2c26c4 에서처럼 uart의 소유권을 console이 지니는 것을 분명히 하여 console의 존재 의미를 살리는 방식으로 role back 하겠습니다.

@coolofficials
Copy link
Collaborator Author

우선 procdump debugging만 하는 정도에서 PR을 마무리하고 console/printer/uart refactoring은 추후에 별도의 issue로 다루기로 해서 close합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants