diff --git a/_config.butterfly.yml b/_config.butterfly.yml index 31433bc..e825c54 100644 --- a/_config.butterfly.yml +++ b/_config.butterfly.yml @@ -3,26 +3,26 @@ # -------------------------------------- nav: - logo: # image - display_title: true + logo: images/common/logo.png + display_title: false fixed: false # fixed navigation bar # Menu 目錄 menu: - # Home: / || fas fa-home - # Archives: /archives/ || fas fa-archive - # Tags: /tags/ || fas fa-tags - # Categories: /categories/ || fas fa-folder-open - # List||fas fa-list: - # Music: /music/ || fas fa-music - # Movie: /movies/ || fas fa-video - # Link: /link/ || fas fa-link - # About: /about/ || fas fa-heart + Home: / || fas fa-home + Archives: /archives/ || fas fa-archive + Tags: /tags/ || fas fa-tags + Categories: /categories/ || fas fa-folder-open + List||fas fa-list: + Music: /music/ || fas fa-music + Movie: /movies/ || fas fa-video + Link: /link/ || fas fa-link + About: /about/ || fas fa-heart # Code Blocks (代碼相關) # -------------------------------------- -highlight_theme: light # darker / pale night / light / ocean / mac / mac light / false +highlight_theme: mac # darker / pale night / light / ocean / mac / mac light / false highlight_copy: true # copy button highlight_lang: true # show the code language highlight_shrink: false # true: shrink the code blocks / false: expand the code blocks | none: expand code blocks and hide the button @@ -33,49 +33,49 @@ code_word_wrap: false # formal: # icon: link || the description || color social: - # fab fa-github: https://github.com/xxxxx || Github || '#24292e' - # fas fa-envelope: mailto:xxxxxx@gmail.com || Email || '#4a7dbe' + fab fa-github: https://github.com/malgcheong || Github || '#24292e' + fas fa-envelope: mailto:skacjddn7@gmail.com || Email || '#4a7dbe' # Image (圖片設置) # -------------------------------------- # Favicon(網站圖標) -favicon: /img/favicon.png +favicon: images/common/favicon.jpg # Avatar (頭像) avatar: - img: https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png + img: images/common/avatar.jpg effect: false # Disable all banner image disable_top_img: false # The banner image of home page -index_img: +index_img: images/common/index_img.jpg # If the banner of page not setting, it will show the top_img -default_top_img: +default_top_img: images/common/index_img.jpg # The banner image of archive page -archive_img: +archive_img: images/common/index_img.jpg # If the banner of tag page not setting, it will show the top_img # note: tag page, not tags page (子標籤頁面的 top_img) -tag_img: +tag_img: images/common/index_img.jpg # The banner image of tag page # format: # - tag name: xxxxx -tag_per_img: +tag_per_img: images/common/index_img.jpg # If the banner of category page not setting, it will show the top_img # note: category page, not categories page (子分類頁面的 top_img) -category_img: +category_img: images/common/index_img.jpg # The banner image of category page # format: # - category name: xxxxx -category_per_img: +category_per_img: images/common/index_img.jpg cover: # display the cover or not (是否顯示文章封面) @@ -84,7 +84,7 @@ cover: archives_enable: true # the position of cover in home page (封面顯示的位置) # left/right/both - position: both + position: left # When cover is not set, the default cover is displayed (當沒有設置cover時,默認的封面顯示) default_cover: # - https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg @@ -96,7 +96,7 @@ error_img: # A simple 404 page error_404: - enable: false + enable: true subtitle: 'Page Not Found' background: https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png @@ -155,8 +155,8 @@ toc: post_copyright: enable: true - decode: false - author_href: + decode: true + author_href: https://malgcheong.github.io/ license: CC BY-NC-SA 4.0 license_url: https://creativecommons.org/licenses/by-nc-sa/4.0/ @@ -175,7 +175,7 @@ reward: # Post edit # Easily browse and edit blog source code online. post_edit: - enable: false + enable: true # url: https://github.com/user-name/repo-name/edit/branch-name/subdirectory-name/ # For example: https://github.com/jerryc127/butterfly.js.org/edit/main/source/ url: @@ -207,8 +207,8 @@ noticeOutdate: footer: owner: enable: true - since: 2020 - custom_text: + since: 2024 + custom_text: Hi, welcome to my blog! copyright: true # Copyright of theme and framework # aside (側邊欄) @@ -216,7 +216,7 @@ footer: aside: enable: true - hide: false + hide: true button: true mobile: true # display on mobile position: right # left or right @@ -231,7 +231,7 @@ aside: enable: true icon: fab fa-github text: Follow Me - link: https://github.com/xxxxxx + link: https://github.com/malgcheong card_announcement: enable: true content: This is my Blog @@ -389,15 +389,15 @@ docsearch: # Share.js # https://github.com/overtrue/share.js sharejs: - enable: true - sites: facebook,twitter,wechat,weibo,qq - + enable: false + sites: facebook,twitter,linkedin + # sites: facebook,twitter,wechat,weibo,qq # AddToAny # https://www.addtoany.com/ addtoany: - enable: false - item: facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link - + enable: true + item: linkedin,email,copy_link + # item: facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link # Comments System # -------------------------------------- @@ -645,7 +645,7 @@ text_align_justify: false background: # Footer Background -footer_bg: false +footer_bg: true # Add mask to header or footer (为 header 或 footer 添加黑色半透遮罩) mask: @@ -730,16 +730,15 @@ beautify: # Global font settings # Don't modify the following settings unless you know how they work (非必要不要修改) font: - global-font-size: + global-font-size: 1.2em code-font-size: - font-family: - code-font-family: - + font-family: Radio Canada Big, Noto Serif KR + code-font-family: monospace, Noto Serif KR # Font settings for the site title and site subtitle # 左上角網站名字 主頁居中網站名字 blog_title_font: - font_link: - font-family: + font_link: https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@600&family=Poetsen+One&family=Radio+Canada+Big&display=swap + font-family: Poetsen One, Noto Serif KR # The setting of divider icon (水平分隔線圖標設置) hr_icon: @@ -749,7 +748,7 @@ hr_icon: # the subtitle on homepage (主頁subtitle) subtitle: - enable: false + enable: true # Typewriter Effect (打字效果) effect: true # Customize typed.js (配置typed.js) diff --git a/_config.yml b/_config.yml index 9daa383..232ac42 100644 --- a/_config.yml +++ b/_config.yml @@ -7,13 +7,13 @@ title: Malgcheong's Blog subtitle: '진솔한 개발 블로그입니다' description: '' keywords: -author: Choeong Woo +author: Cheongwoo Nam language: en timezone: '' # URL ## Set your site url here. For example, if you use GitHub Page, set url as 'https://username.github.io/project' -url: http://example.com +url: https://malgcheong.github.io/ permalink: :year/:month/:day/:title/ permalink_defaults: pretty_urls: @@ -101,4 +101,6 @@ theme: butterfly # Deployment ## Docs: https://hexo.io/docs/one-command-deployment deploy: - type: '' + type: git + repo: https://github.com/malgcheong/malgcheong.github.io.git + branch: gh-pages diff --git a/package-lock.json b/package-lock.json index 612877a..13e1a55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,8 @@ "name": "hexo-site", "version": "0.0.0", "dependencies": { - "hexo": "^7.0.0", + "hexo": "^7.3.0", + "hexo-deployer-git": "^4.0.0", "hexo-generator-archive": "^2.0.0", "hexo-generator-category": "^2.0.0", "hexo-generator-index": "^3.0.0", @@ -1022,19 +1023,19 @@ } }, "node_modules/hexo": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/hexo/-/hexo-7.1.1.tgz", - "integrity": "sha512-u6aJXG1npYkZJLl7QEOeTdm9hOwxfsLmFp4qAQVF0OAuNaikrKORjgNsjPmrWwI/tIObwjVJnEUJnV7S+NnUlw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/hexo/-/hexo-7.3.0.tgz", + "integrity": "sha512-dOe8mzBKrvjubW5oBmyhcnQDpC+M2xmAMLae5K+o+SkHxyvAhShkS2VQZoTsOLIJKY6xilv7dzCjCvE7ol/NHQ==", "dependencies": { "abbrev": "^2.0.0", "archy": "^1.0.0", "bluebird": "^3.7.2", - "hexo-cli": "^4.3.0", + "hexo-cli": "^4.3.2", "hexo-front-matter": "^4.2.1", - "hexo-fs": "^4.1.1", + "hexo-fs": "^4.1.3", "hexo-i18n": "^2.0.0", "hexo-log": "^4.0.1", - "hexo-util": "^3.0.1", + "hexo-util": "^3.3.0", "js-yaml": "^4.1.0", "js-yaml-js-types": "^1.0.0", "micromatch": "^4.0.4", @@ -1049,7 +1050,7 @@ "text-table": "^0.2.0", "tildify": "^2.0.0", "titlecase": "^1.1.3", - "warehouse": "^5.0.0" + "warehouse": "^5.0.1" }, "bin": { "hexo": "bin/hexo" @@ -1063,16 +1064,16 @@ } }, "node_modules/hexo-cli": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/hexo-cli/-/hexo-cli-4.3.1.tgz", - "integrity": "sha512-nYe7yJhXT7MwlDEpIAjneMfz0wnWTdIhRv+cVW2OPTw8JtG2X+8Y/sYhPDvQz/ZqjFRZ4qgiKFXN5orFJ/u1vg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/hexo-cli/-/hexo-cli-4.3.2.tgz", + "integrity": "sha512-druJeBgLpG9ncDS5AhBHdAXk0G4CFj8Qes09pApyZ6bR+nJW1JYiDMuilhudaKDdq+1l49jWXVTidkcb7p0Jbw==", "dependencies": { "abbrev": "^2.0.0", "bluebird": "^3.7.2", "command-exists": "^1.2.9", "hexo-fs": "^4.1.1", "hexo-log": "^4.0.1", - "hexo-util": "^2.5.0", + "hexo-util": "^3.3.0", "minimist": "^1.2.5", "picocolors": "^1.0.0", "resolve": "^1.20.0", @@ -1085,7 +1086,23 @@ "node": ">=14" } }, - "node_modules/hexo-cli/node_modules/dom-serializer": { + "node_modules/hexo-deployer-git": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hexo-deployer-git/-/hexo-deployer-git-4.0.0.tgz", + "integrity": "sha512-28t1Q+4taB/UaBAP52W3mD/wcCwa2y2zBieUfBJFBZudbmVgiKJB5YedYILeyI5QByaUKAOwoupmdTbocdQ+CQ==", + "dependencies": { + "bluebird": "^3.7.2", + "hexo-fs": "^4.0.0", + "hexo-util": "^2.7.0", + "luxon": "^3.0.4", + "nunjucks": "^3.2.3", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/hexo-deployer-git/node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", @@ -1098,7 +1115,7 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/hexo-cli/node_modules/dom-serializer/node_modules/entities": { + "node_modules/hexo-deployer-git/node_modules/dom-serializer/node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", @@ -1106,7 +1123,7 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/hexo-cli/node_modules/domhandler": { + "node_modules/hexo-deployer-git/node_modules/domhandler": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", @@ -1120,7 +1137,7 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/hexo-cli/node_modules/domutils": { + "node_modules/hexo-deployer-git/node_modules/domutils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", @@ -1133,7 +1150,7 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/hexo-cli/node_modules/entities": { + "node_modules/hexo-deployer-git/node_modules/entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", @@ -1144,7 +1161,7 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/hexo-cli/node_modules/hexo-util": { + "node_modules/hexo-deployer-git/node_modules/hexo-util": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/hexo-util/-/hexo-util-2.7.0.tgz", "integrity": "sha512-hQM3h34nhDg0bSe/Tg1lnpODvNkz7h2u0+lZGzlKL0Oufp+5KCAEUX9wal7/xC7ax3/cwEn8IuoU75kNpZLpJQ==", @@ -1162,7 +1179,7 @@ "node": ">=12.4.0" } }, - "node_modules/hexo-cli/node_modules/htmlparser2": { + "node_modules/hexo-deployer-git/node_modules/htmlparser2": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", @@ -1192,114 +1209,19 @@ } }, "node_modules/hexo-fs": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-4.1.1.tgz", - "integrity": "sha512-aDysNTyv8ElcerbFVbPLRXnYt+QDY6gAOZZ5DLbCxudY0Ywppqd+uZ03gZ2BDypIBvmNB27WYWYz76M+Yv/YXw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-4.1.3.tgz", + "integrity": "sha512-Q92zQ5PlVDouvSWFLXQoFSTLIUIODikUJs2BfAXQglyOEjN1dOQn1Z5Nimk/7GHof17R5h/uObCQLnZAjzI2tg==", "dependencies": { "bluebird": "^3.7.2", "chokidar": "^3.5.3", "graceful-fs": "^4.2.10", - "hexo-util": "^2.7.0" + "hexo-util": "^3.0.1" }, "engines": { "node": ">=14" } }, - "node_modules/hexo-fs/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/hexo-fs/node_modules/dom-serializer/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/hexo-fs/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/hexo-fs/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/hexo-fs/node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/hexo-fs/node_modules/hexo-util": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/hexo-util/-/hexo-util-2.7.0.tgz", - "integrity": "sha512-hQM3h34nhDg0bSe/Tg1lnpODvNkz7h2u0+lZGzlKL0Oufp+5KCAEUX9wal7/xC7ax3/cwEn8IuoU75kNpZLpJQ==", - "dependencies": { - "bluebird": "^3.5.2", - "camel-case": "^4.0.0", - "cross-spawn": "^7.0.0", - "deepmerge": "^4.2.2", - "highlight.js": "^11.0.1", - "htmlparser2": "^7.0.0", - "prismjs": "^1.17.1", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=12.4.0" - } - }, - "node_modules/hexo-fs/node_modules/htmlparser2": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", - "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.2", - "domutils": "^2.8.0", - "entities": "^3.0.1" - } - }, "node_modules/hexo-generator-archive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hexo-generator-archive/-/hexo-generator-archive-2.0.0.tgz", @@ -1869,6 +1791,14 @@ "tslib": "^2.0.3" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -3685,19 +3615,19 @@ } }, "hexo": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/hexo/-/hexo-7.1.1.tgz", - "integrity": "sha512-u6aJXG1npYkZJLl7QEOeTdm9hOwxfsLmFp4qAQVF0OAuNaikrKORjgNsjPmrWwI/tIObwjVJnEUJnV7S+NnUlw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/hexo/-/hexo-7.3.0.tgz", + "integrity": "sha512-dOe8mzBKrvjubW5oBmyhcnQDpC+M2xmAMLae5K+o+SkHxyvAhShkS2VQZoTsOLIJKY6xilv7dzCjCvE7ol/NHQ==", "requires": { "abbrev": "^2.0.0", "archy": "^1.0.0", "bluebird": "^3.7.2", - "hexo-cli": "^4.3.0", + "hexo-cli": "^4.3.2", "hexo-front-matter": "^4.2.1", - "hexo-fs": "^4.1.1", + "hexo-fs": "^4.1.3", "hexo-i18n": "^2.0.0", "hexo-log": "^4.0.1", - "hexo-util": "^3.0.1", + "hexo-util": "^3.3.0", "js-yaml": "^4.1.0", "js-yaml-js-types": "^1.0.0", "micromatch": "^4.0.4", @@ -3712,24 +3642,37 @@ "text-table": "^0.2.0", "tildify": "^2.0.0", "titlecase": "^1.1.3", - "warehouse": "^5.0.0" + "warehouse": "^5.0.1" } }, "hexo-cli": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/hexo-cli/-/hexo-cli-4.3.1.tgz", - "integrity": "sha512-nYe7yJhXT7MwlDEpIAjneMfz0wnWTdIhRv+cVW2OPTw8JtG2X+8Y/sYhPDvQz/ZqjFRZ4qgiKFXN5orFJ/u1vg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/hexo-cli/-/hexo-cli-4.3.2.tgz", + "integrity": "sha512-druJeBgLpG9ncDS5AhBHdAXk0G4CFj8Qes09pApyZ6bR+nJW1JYiDMuilhudaKDdq+1l49jWXVTidkcb7p0Jbw==", "requires": { "abbrev": "^2.0.0", "bluebird": "^3.7.2", "command-exists": "^1.2.9", "hexo-fs": "^4.1.1", "hexo-log": "^4.0.1", - "hexo-util": "^2.5.0", + "hexo-util": "^3.3.0", "minimist": "^1.2.5", "picocolors": "^1.0.0", "resolve": "^1.20.0", "tildify": "^2.0.0" + } + }, + "hexo-deployer-git": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hexo-deployer-git/-/hexo-deployer-git-4.0.0.tgz", + "integrity": "sha512-28t1Q+4taB/UaBAP52W3mD/wcCwa2y2zBieUfBJFBZudbmVgiKJB5YedYILeyI5QByaUKAOwoupmdTbocdQ+CQ==", + "requires": { + "bluebird": "^3.7.2", + "hexo-fs": "^4.0.0", + "hexo-util": "^2.7.0", + "luxon": "^3.0.4", + "nunjucks": "^3.2.3", + "picocolors": "^1.0.0" }, "dependencies": { "dom-serializer": { @@ -3809,82 +3752,14 @@ } }, "hexo-fs": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-4.1.1.tgz", - "integrity": "sha512-aDysNTyv8ElcerbFVbPLRXnYt+QDY6gAOZZ5DLbCxudY0Ywppqd+uZ03gZ2BDypIBvmNB27WYWYz76M+Yv/YXw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-4.1.3.tgz", + "integrity": "sha512-Q92zQ5PlVDouvSWFLXQoFSTLIUIODikUJs2BfAXQglyOEjN1dOQn1Z5Nimk/7GHof17R5h/uObCQLnZAjzI2tg==", "requires": { "bluebird": "^3.7.2", "chokidar": "^3.5.3", "graceful-fs": "^4.2.10", - "hexo-util": "^2.7.0" - }, - "dependencies": { - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "dependencies": { - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - } - } - }, - "domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==" - }, - "hexo-util": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/hexo-util/-/hexo-util-2.7.0.tgz", - "integrity": "sha512-hQM3h34nhDg0bSe/Tg1lnpODvNkz7h2u0+lZGzlKL0Oufp+5KCAEUX9wal7/xC7ax3/cwEn8IuoU75kNpZLpJQ==", - "requires": { - "bluebird": "^3.5.2", - "camel-case": "^4.0.0", - "cross-spawn": "^7.0.0", - "deepmerge": "^4.2.2", - "highlight.js": "^11.0.1", - "htmlparser2": "^7.0.0", - "prismjs": "^1.17.1", - "strip-indent": "^3.0.0" - } - }, - "htmlparser2": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", - "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.2", - "domutils": "^2.8.0", - "entities": "^3.0.1" - } - } + "hexo-util": "^3.0.1" } }, "hexo-generator-archive": { @@ -4312,6 +4187,11 @@ "tslib": "^2.0.3" } }, + "luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==" + }, "marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", diff --git a/package.json b/package.json index 6c7fbf4..27fa0d9 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "version": "7.1.1" }, "dependencies": { - "hexo": "^7.0.0", + "hexo": "^7.3.0", + "hexo-deployer-git": "^4.0.0", "hexo-generator-archive": "^2.0.0", "hexo-generator-category": "^2.0.0", "hexo-generator-index": "^3.0.0", diff --git a/source/_posts/Common memory-related bugs in C program.md b/source/_posts/Common memory-related bugs in C program.md new file mode 100644 index 0000000..faeb776 --- /dev/null +++ b/source/_posts/Common memory-related bugs in C program.md @@ -0,0 +1,143 @@ +--- +title: C프로그램에서의 공통된 메모리 관련 버그 +date: 2024-04-17 11:24:40 +categories: + - C +tags: + - SW 사관학교 정글 +--- + +9.11 C프로그램에서의 공통된 메모리 관련 버그 참고 + +### 1. 잘못된 포인터의 역참조 +```c +scanf("%d", val); +``` +scanf는 **val의 값을 주소로 해석**하고 **이 위치에 워드를 쓰려고** 한다. +최상의 경우에 프로그램은 즉시 예외를 발생시키고 종료한다. 최악의 경우는 val의 값이 유효한 가상메모리의 읽기/쓰기 영역에 대응되어 메모리를 덮어쓰고, 대개 치명적이고 혼란을 일으키는 결과를 훨씬 뒤에 갖게 된다. + +### 2. 초기화되지 않은 메모리를 읽는 경우 +- bss메모리 위치(초기값 없는 전역변수, static으로 선언된 변수, 배열)들은 항상 로더에 의해 0으로 초기화된다. +- heap메모리 위치는 calloc으로 할당해야 0으로 초기화됨. malloc으로 초기화하면 그렇지 않다. + +### 3. 스택 버퍼 오버플로우 허용하기 + +```c +#include "stdio.h" + +MAX_LENGTH = 4; + +int main() +{ +char str1[MAX_LENGTH]; +char str2[MAX_LENGTH]; + +// gets 함수를 사용하여 문자열 입력 받기 +printf("Enter a string using gets: "); +gets(str1); +printf("String entered using gets: %s\n", str1); + +// fgets 함수를 사용하여 문자열 입력 받기 +printf("Enter a string using fgets: "); +fgets(str2, sizeof(str2), stdin); +// fgets는 개행 문자도 읽어들이므로 개행 문자 제거 +str2[strcspn(str2, "\n")] = '\0'; +printf("String entered using fgets: %s\n", str2); + +return 0; +} +``` + +![](/images/c/1.png) + +### 4. 포인터와 이들이 가리키는 객체들이 같은 크기라고 가정하기 +```c +/* Create an nxm array */ +int **makeArray1(int n, int m){ + int i; + int **A = (int **)malloc(n * sizeof(int)); + + for (int i = 0; i < n; i++) + A[i] = (int *)malloc(m * sizeof(int)); +} +``` + +### 5. Off-by-One 에러 만들기 +```c +/* Create an nxm array */ +int **makeArray2(int n, int m){ + int i; + int **A = (int **)malloc(n * sizeof(int *)); + + for (int i = 0; i <= n; i++) + A[i] = (int *)malloc(m * sizeof(int)); +} +``` + +### 6. 포인터가 가리키는 객체 대신에 포인터 참조하기 +```c +int *binheapDelete(int **binheap, int *size) +{ + int *packet = binheap[0]; + + binheap[0] = binheap[*size - 1]; + *size--; /* This should be (*size)--*/ + heapify(binheap, *size, 0); + return(packet); +} +``` +6번 줄에서, **--와 * 연산자들은 동일한 우선순위**를 가지고 우에서 좌로 결합하기 때문에 이 코드는 실제로는 가리키는 정수 값 대신에 **포인터 자신을 감소**시킨다. + +### 7. 포인터 연산에 대한 오해 +```c +int *search(int *p, int val) +{ + while(*p && *p != val) + p += sizeof(int); /* Should be p++ */ + return p; +} +``` + +### 8. 존재하지 않는 변수 참조하기 +```c +int *stackref() +{ + int val; + + return &val; +} +``` +`stackref` 함수가 호출될 때마다 `val`이라는 지역 변수가 생성되고 해당 변수의 주소를 반환합니다. 그러나 `val`은 함수가 종료되면 스택 프레임과 함께 사라지는 지역 변수이므로, **`stackref` 함수가 종료되면 비록 포인터가 여전히 유효한 메모리 주소를 가리키지만, 더 이상 유효한 변수를 가리키지는 않는다.** + +따라서 `stackref` 함수를 호출할 때마다 새로운 지역 변수 `val`이 생성되고 그 주소를 반환하지만, 이러한 주소는 함수가 종료된 후에는 더 이상 유효하지 않습니다. 다시 호출될 때마다 새로운 지역 변수가 생성되므로, 이전에 반환된 주소는 다른 지역 변수를 가리킬 것입니다. + +따라서 이러한 함수의 반환 값인 포인터는 재사용될 수 없으며, 사용하려면 함수가 반환하는 포인터를 별도의 변수에 저장해야 합니다. + +### 9. 가용 힙 블록 내 데이터 참조하기 +```c +int *healpref(int n, int m) +{ +int i; +int *x, *y; + +x = (int *)malloc(n * sizeof(int)); +free(x); +y = (int *)malloc(n * sizeof(int)); + +for (int i = 0; i < m; i++) + y[i] = x[i]++; /* Oops! x[i] is a word in a free block */ + +return y; +} +``` +### 10. 메모리 누수 leak 유발 +```c +void leak(int n) +{ + int *x = (int *)malloc(n * sizeof(int)); + + return; /* x is garbage at this pointer */ +} +``` +메모리 누수는 엔지니어가 **할당된 블록들을 반환하는 것을 잊어서** 힙에 가비지를 부주의하게 만들 때 일어나는 조용한 살인자다. +만일 leak이 자주 호출되면, 힙은 점차적으로 가비지로 가득 차게 되고, 최악의 경우 전체 가상 주소공간을 소모하게 된다. 메모리 누수는 특히 데몬 daemon, 서버와 같이 종료되지 않는 프로그램들의 경우에 심각하다. \ No newline at end of file diff --git a/source/_posts/OS Project 1 WIL.md b/source/_posts/OS Project 1 WIL.md new file mode 100644 index 0000000..40682e7 --- /dev/null +++ b/source/_posts/OS Project 1 WIL.md @@ -0,0 +1,214 @@ +--- +title: "OS Project 1 WIL" +date: 2024-05-02 +excerpt: "" + +categories: [PINTOS] +tags: [SW 사관학교 정글] +cover: /images/pintos/part1 thread.jpg + +--- +# 1. Alarm Clock +### timer interrupt +1. timer는 하드웨어를 통해 초당 PIT_FREQ 회 interrupt가 발생함. +2. 4tic마다 time slicing하여 멀티 태스킹을 할 스레드들이 골고루 cpu 연산 작업을 하기 위해 timer interrupt를 사용함. +3. interrupt는 지금 실행중인 thread를 잠깐 멈추고 그 interrupt에 해당하는 핸들러를 수행하도록 함. interrupt 핸들러가 수행되면 기존에 작업하던 스레드로 돌아감. + +### Problem +1. pintos는 busy waitng 방식으로, ready queue에서 깨어날지 안할지를 thread_yield ()를 매번 발생시켜 cpu에서 확인함. cpu에서 확인하기 때문에 그만큼 쓸데없는 자원을 많이 소모함. + +### Solve +1. sleep list를 만들어 thread가 wait해야할 시간동안 sleep list에 저장했다가 ready queue로 옮기도록 구현함. +```c +// 스레드를 sleep 시켜서 sleep_list에 넣습니다. +void thread_sleep(int64_t ticks) { + struct thread *curr = thread_current(); + enum intr_level old_level; + + old_level = intr_disable(); + + if (curr != idle_thread) { + curr->wakeup_ticks = ticks; + list_push_front(&sleep_list, &curr->elem); + next_awake_ticks(curr->wakeup_ticks); + thread_block(); + } + + intr_set_level(old_level); +} +``` +2. thread 구조체에 자신의 thread가 일어날 시간인 wakeup_ticks를 설정함. thread가 일어날 단위가 tick이라서 timer interrupt 핸들러에서 sleep list를 확인하고 wakeup_ticks을 통해 wake up할 스레드를 찾으면 sleep list에서 삭제하고 ready queue에 추가함. +```c +// 일어날 시간이 되면 대기 큐에 업데이트 후 sleep_list에서 remove +void thread_wakeup(int64_t ticks) { + struct list_elem *e = list_begin(&sleep_list); // sleep_list 시작부터 순회 + + if (ticks < next_tick_to_awake) + return; + + while (e != list_end(&sleep_list)) // sleep_list에 마지막까지 봄 + { + struct thread *t = list_entry(e, struct thread, elem); + + if (t->wakeup_ticks <= ticks) { + e = list_remove(e); + threaunblock(t); + } + else { + e = list_next(e); + } + } +} +``` +3. sleep list 조회의 효율성을 위해 가장 빨리 깨어날 thread의 시간을 전역변수로 설정함. 왜냐하면 지금 os의 tick이 sleep list에서 가장 빨리 일어나야할 thread보다 작다면 sleep list를 조회할 필요 없다. 깨울 thread가 있는 경우에만 sleep list를 조회했다. +```c +static int64_t next_tick_to_awake = NULL; // 전역변수로 선언 + +// 일어날 시간이 되면 대기 큐에 업데이트 후 sleep_list에서 remove +void thread_wakeup(int64_t ticks) { + ... + if (ticks < next_tick_to_awake) + return; + ... +} +``` + +# 2. Priority Scheduling +### Problem +1. 기존에 구현되어 있던 것은 round-robin 방식임. +2. 파일을 다운하면서 게임을 하듯이 우선순위가 높은 게임이 먼저 실행되기 위해서 thread마다 우선순위를 부여해 스케줄링할 필요가 있음. + +### Solve +1. ready queue에 priority를 내림차순으로 정렬해 우선순위가 높은 thread를 CPU에 thread_yield ()될 수 있도록 구현함. +```c +/* CPU를 양보합니다. 현재 스레드는 슬립 상태로 전환되지 않으며, + 스케줄러의 변덕에 따라 즉시 다시 스케줄될 수 있습니다. */ +void thread_yield(void) { + struct thread *curr = thread_current(); + enum intr_level old_level; + + ASSERT(!intr_context()); + + old_level = intr_disable(); + if (curr != idle_thread) { + // list_push_back(&ready_list, &curr->elem); + list_insert_desc_ordered(&ready_list, &curr->elem, compare_priority, PRIORITY); + } + do_schedule(THREAD_READY); + intr_set_level(old_level); +} +``` +```c +/* 값 비교. t1의 우선순위가 낮은 경우 true*/ +bool compare_priority(struct list_elem *e1, struct list_elem *e2, void *aux) { + struct thread *t1 = list_entry(e1, struct thread, elem); + struct thread *t2 = list_entry(e2, struct thread, elem); + int t1_priority = t1->priority; + int t2_priority = t2->priority; + + // list_insert_desc_ordered에서 e1, e2 순서 반대여서 첫번째 요소가 작을 경우가 참임 + if (t1_priority < t2_priority) { + return true; + } + return false; +} +``` +2. thread가 생성 될 때와 cpu의 priority가 변경 될 때 ready queue의 첫 thread의 priority와 cpu에 올라간 thread의 priority를 비교해 thread_yield () 할 수 있도록 구현함. 높은 우선순위의 스레드가 생기자마자 해당 스레드를 cpu에서 사용하기 위해서임. +```c +tid_t thread_create(const char *name, int priority, thread_func *function, void *aux) { + ... + /* 준비 큐에 추가. */ + thread_unblock(t); + + // 우선순위 스케줄링 + test_max_priority(); + ... +} +``` +```c +/* 현재 스레드의 우선순위를 NEW_PRIORITY로 설정합니다. */ +void thread_set_priority(int new_priority) { + thread_current()->priority = new_priority; + test_max_priority(); +} +``` +```c +// 우선순위 스케줄링 하는 함수 +void test_max_priority(void) { + struct thread *curr = thread_current(); + struct list_elem *highest_elem = list_begin(&ready_list); + if (list_end(&ready_list) == (highest_elem)) { + return; + } + + if (compare_priority(&curr->elem, highest_elem, NULL)) { + thread_yield(); + } +} +``` + +# 3. Priority Scheduling - priority inversion +### Problem +1. 낮은 우선순위의 thread가 공유자원에 lock을 건 채로 cpu에서 연산작업을 하다가 +높은 우선순위의 thread가 생성되면 thread_yield ()가 발생해 context switching이 발생한다. +높은 우선순위의 thread가 cpu에 올라가 동일한 공유자원에 lock을 얻고 싶어도 cpu를 반환하게 되고 +우선순위가 낮은 thread가 먼저 실행되는 우선순위 역전의 문제가 발생한다. +2. 혹은 낮은 우선순위의 thread가 lock을 쥔채로 대기 상태로 들어가고 +해당 lock을 갖고 싶은 높은 우선순위의 thread가 계속 cpu를 선점한다면 dead lock이 발생한다. + +### Solve (donation) +1. 위의 문제를 해결하기 위해선 priority donation이 필요하다. +2. lock 잠금시 이미 lock을 소유한 thread에게 높은 우선순위의 thread의 priority를 상속한다. +```c +void donate_priority(void) { + + int depth; + struct thread *curr = thread_current(); + + for (depth = 0; depth < 8 ; depth++) { + if(!curr->wait_on_lock) + break; + struct thread *holder = curr->wait_on_lock->holder; + holder->priority = curr->priority; + curr = holder; + } +} +``` +3. lock 해제시 priority를 반환한다. 하지만 그 lock을 원하는 우선순위의 thread로 바뀌거나 없다면 자기 자신의 priority로 바뀐다. +```c +void lock_release (struct lock *lock) { + ASSERT (lock != NULL); + ASSERT (lock_held_by_current_thread (lock)); + + remove_with_lock(lock); + refresh_priority(); + + lock->holder = NULL; + sema_up (&lock->semaphore); +} +``` +```c +void remove_with_lock(struct lock *lock) { + struct list_elem *e; + struct thread *curr = thread_current(); + + for (e = list_begin(&curr->donations); e != list_end(&curr->donations); e = list_next(e)) { + struct thread *t = list_entry(e, struct thread, donation_elem); + if (t->wait_on_lock == lock) + list_remove(&t->donation_elem); + } +} +``` +```c +void refresh_priority(void) { + struct thread *curr = thread_current(); + curr->priority = curr->init_priority; + + if (!list_empty(&curr->donations)) { + list_sort(&curr->donations, thread_compare_donate_priority, NULL); + struct thread *front = list_entry(list_front(&curr->donations), struct thread, donation_elem); + if (front->priority > curr->priority) + curr->priority = front->priority; + } +} +``` \ No newline at end of file diff --git a/source/_posts/OS Project 2 WIL.md b/source/_posts/OS Project 2 WIL.md new file mode 100644 index 0000000..392d6d8 --- /dev/null +++ b/source/_posts/OS Project 2 WIL.md @@ -0,0 +1,431 @@ +--- +title: "OS Project 2 WIL" +date: 2024-05-14 +excerpt: "" + +categories: [PINTOS] +tags: [SW 사관학교 정글] +cover: /images/pintos/part2 user program.jpg + +--- +sw사관학교 정글 과정중 pintos project 2 진행중에 구현한 fork 의 과정을 추척하는 글을 작성 해보려고 한다. + +## 목차 + +- pintos에서의 fork +- fork 과정 추적 + - 1. userprogram 에서 fork 함수 호출 + 2. lib/user/syscall.c 에서의 처리 + 3. syscall-entry.S + 4. userprog/syscall.c 의 syscall_handler 함수 + 5. userprog/process.c 의 process_fork() + 6. threads/thread.c thread_create() 함수 + 7. do_fork + 8. 다시 process_fork +- 결론 + +## pintos에서의 fork  + +Pintos에서 'fork' 구현 목표는 부모 프로세스의 주소 공간을 정확하게 복사하여 자식 프로세스에 할당하는 것이다.  + +1. **fd** **복제**: 부모 프로세스의 fd를 자식에게도 복사. +2. **주소공간 복사:** pintos는 페이지 단위로 메모리를 관리하므로, 각 페이지를 자식 프로세스의 페이지에 복사 +3. **CPU 상태 복제:** 부모 프로세스의 cpu  레지스터 상태를 자식 프로세스에게 복사. >> (자식 프로세스가 부모 프로세스가 중단된 지점부터 실행을 계속 할 수 있도록 하기위해) +4. **자식 프로세스의 실행:**  모든 복사가 완료 된 후, 자식 프로세스는 스케줄러에 의해 레디 큐에 추가됨. + +> 개인적으로 과정 (3.) 이 헷갈렸었다. **시스템 콜 핸들러가 동작하기 직전의** 부모 프로세스의 cpu 레지스터 상태를 복사해야 함에 주의해야한다. _후술 하겠지만 이는 thread 구조체의 tf 에 값이 아니다!!!!_ + +> 2. 주소공간 복사의 경우 쓰기 시 복사 (copy-on-write) 기법을 사용해 메모리 사용을 높일 수 있지만, 우선 우리는 무조건 다 복사하도록 구현했다. + +## fork 과정 추적 + +### 1. userprogram 에서 fork 함수 호출 + +fork 가 언제 일어나는가? 유저 프로그램에서 fork() 함수를 호출(사용)했을 때 동작을 시작한다. 우리의 핀토스 과제에서는 테스트 케이스로 유저프로그램이 구현되어있다. + +> 해당 과정에서는 **tests/userprog/fork-onec.c** 파일을 예시로 작성하겠다. + +```c +/* Forks and waits for a single child process. */ + +#include +#include "tests/lib.h" +#include "tests/main.h" + +void +test_main (void) +{ + int pid; + + if ((pid = fork("child"))){ + int status = wait (pid); + msg ("Parent: child exit status is %d", status); + } else { + msg ("child run"); + exit(81); + } +} +``` + +**fork("child")** 로 시스템 콜을 호출한다. + +### 2. lib/user/syscall.c 에서의 처리 + +```c +#include +#include +#include "../syscall-nr.h" + +__attribute__((always_inline)) +static __inline int64_t syscall (uint64_t num_, uint64_t a1_, uint64_t a2_, + uint64_t a3_, uint64_t a4_, uint64_t a5_, uint64_t a6_) { + int64_t ret; + register uint64_t *num asm ("rax") = (uint64_t *) num_; + register uint64_t *a1 asm ("rdi") = (uint64_t *) a1_; + register uint64_t *a2 asm ("rsi") = (uint64_t *) a2_; + register uint64_t *a3 asm ("rdx") = (uint64_t *) a3_; + register uint64_t *a4 asm ("r10") = (uint64_t *) a4_; + register uint64_t *a5 asm ("r8") = (uint64_t *) a5_; + register uint64_t *a6 asm ("r9") = (uint64_t *) a6_; + + __asm __volatile( + "mov %1, %%rax\n" + "mov %2, %%rdi\n" + "mov %3, %%rsi\n" + "mov %4, %%rdx\n" + "mov %5, %%r10\n" + "mov %6, %%r8\n" + "mov %7, %%r9\n" + "syscall\n" + : "=a" (ret) + : "g" (num), "g" (a1), "g" (a2), "g" (a3), "g" (a4), "g" (a5), "g" (a6) + : "cc", "memory"); + return ret; +} + +/* Invokes syscall NUMBER, passing argument ARG0, and returns the + return value as an `int'. */ +#define syscall1(NUMBER, ARG0) ( \ + syscall(((uint64_t) NUMBER), \ + ((uint64_t) ARG0), 0, 0, 0, 0, 0)) + + +pid_t +fork (const char *thread_name){ + return (pid_t) syscall1 (SYS_FORK, thread_name); +} +``` + +해당 파일의 1. 에서의 **fork("child")** 는 위 파일의 **fork ()**를 만나 **syscall1** 매크로를 통해 가공되어 **syscall** 함수를 호출한다. + +> **fork("child")** >>> **syscall1 (2, "child")** >>> **syscall ( 2, "child", 0, 0, 0, 0, 0)** + +어셈블리언어를 보면 해당하는 인자들을 레지스터리 값에 넣고 syscall을 부른다. + +syscall을 부르면 MSR_LSTAR 이라는 주소를 찾아가 그 주소에 담긴 값(함수주소)을 실행한다. + +__ + +```c +#define MSR_LSTAR 0xc0000082 /* Long mode SYSCALL target */ /* Long mode SYSCALL target */ +``` + + MSR_LSTAR는 위와 같이 선언되어있다. + +해당값에는 어떤 함수가 매핑되어있을까? + +바로 + +__ + +```c +void +syscall_init (void) { + write_msr(MSR_STAR, ((uint64_t)SEL_UCSEG - 0x10) << 48 | + ((uint64_t)SEL_KCSEG) << 32); + write_msr(MSR_LSTAR, (uint64_t) syscall_entry); +``` + +해당 부분을 통해 **MSR_LSTAR** 주소에 **syscall_entry** 함수 주소를 넣어주었기 때문에 **syscall** 을 부르면 **userprog/syscall-entry.S** 가 실행된다. + +### 3. syscall-entry.S + +해당 파일의 코드가 실행이 되면 어떤일이 일어나는가? + +![](https://blog.kakaocdn.net/dn/uKNS3/btsHouk7uNr/VxUZkzkSksqQHHaeCbfFYk/img.png) + +_<그림 syscall-entry.S 파일이 하는 일>_ + +위 그림처럼 현재 실행중이던 부모 프로세스의 레지스터 값들을 **부모 프로세스의 (커널)스택영역 상단**에 넣는다. + +>  **struct thread->tf 에 넣는 것이 아니다!!** +> thread 구조체의 tf 에는 언제 값을 저장하는가? 바로 스케줄링이 일어나서 문맥전환 context switching 이 일어날때 스레드 구조체의 tf 에 값을 저장한다. 그러니 tf 에 있는 intr_frame 값들은 **현재 최신 상태의 (직전상태의) cpu 실행 값들이 아니다.** 그래서 만약 tf 값을 자식 프로세스에게 복사한다면 fork 이전 시점의 실행과정을 복사하게 될 수도 있어서 tf 값이아니라 부모스레드 커널 스택영역의 최상단의 intr_frame 값을 복사해야한다. + +위 과정이 끝난후 (해당 파일 46라인 참조) **syscall_handle**r를 호출한다. + +### 4. userprog/syscall.c 의 syscall_handler 함수 + +```c +void syscall_handler(struct intr_frame *f UNUSED) { + + int sys_num = f->R.rax; + + switch (sys_num) { + case SYS_HALT: + halt(); + break; + case SYS_WRITE: + f->R.rax = write(f->R.rdi, f->R.rsi, f->R.rdx); + break; + case SYS_EXIT: + exit(f->R.rdi); + break; + case SYS_FORK: + f->R.rax = fork(f->R.rdi); + break; +``` + +이전 과정에서 fork를 할 스레드(부모) 의 커널 스택 최상단에 intr_frame을 넣었고 해당 함수의 인자로(***f**) 넘어왔다. + +switch 문에 fork 부분에 걸려서 우리가 구현한 fork()함수가 실행된다. + +```c +pid_t fork (const char *thread_name) { + check_address(thread_name); + struct intr_frame *if_ = pg_round_up(&thread_name) - sizeof(struct intr_frame); + return process_fork(thread_name, if_); +} +``` + +**thread_name** 이 f->R.rax 이므로 **pg_round_up(&thread_name)**를 하게 되면 해당 스레드(fork를 할 스레드, 부모 스레드) 영역의최상단이 나오고 최상단에는 직전의 cpu 상태를 저장했다. 그 주소에서 intr_frame 사이즈 만큼 주소를 내려주면 ***f**의 주소가 나온다!!! + +>  근데 그냥 처음부터 인자로 주면될텐데 왜 인자 하나로 구현이 되어있었을까? 이에 대한 답은 아직 못구했다. + +이렇게 구한 **f(fork 를 하기 직전의 cpu 상태 정보)**를 process_fork 인자로 넘겨주면된다. + +### 5. userprog/process.c 의 process_fork() + +```c +tid_t process_fork(const char *name, struct intr_frame *if_ UNUSED) { + /* Clone current thread to new thread.*/ + + struct thread *curr = thread_current(); + + tid_t tid = thread_create(name, PRI_DEFAULT, __do_fork, if_); + if(tid == TID_ERROR) + return TID_ERROR; + + struct thread *child = get_child_with_pid(tid); // child_list안에서 만들어진 child thread를 찾음 + sema_down(&child -> fork_sema); // 자식이 메모리에 load될 때까지 기다림(blocked) + if (child -> exit_status == -1) + return TID_ERROR; + + return tid; +} +``` + +위 함수로 오게되어 우선 자식이 될 스레드를 생성한다. 그런데 이제 **do_fork** 함수 주소와 **if_** (방금 넘겨준 fork하기 직전까지의 cpu 상태정보)를 담아서 생성한다. + +**thread_create()** 로 가보자 + +### 6. threads/thread.c thread_create() 함수 + +```c +tid_t thread_create(const char *name, int priority, thread_func *function, void *aux) { + struct thread *t; + tid_t tid; + + ASSERT(function != NULL); + + /* 스레드 할당. */ + /* Allocate thread. */ + t = palloc_get_page(PAL_ZERO); + if (t == NULL) { + palloc_free_page(t); + return TID_ERROR; + } + + /* 스레드 초기화. */ + /* Initialize thread. */ + init_thread(t, name, priority); + tid = t->tid = allocate_tid(); + + /* kernel_thread 호출 시 스케줄링됩니다. + * 주의) rdi는 첫 번째 인자이며, rsi는 두 번째 인자입니다. */ + t->tf.rip = (uintptr_t)kernel_thread; + t->tf.R.rdi = (uint64_t)function; + t->tf.R.rsi = (uint64_t)aux; + t->tf.ds = SEL_KDSEG; + t->tf.es = SEL_KDSEG; + t->tf.ss = SEL_KDSEG; + t->tf.cs = SEL_KCSEG; + t->tf.eflags = FLAG_IF; + + // for project 2 sys call + t->fdt = palloc_get_page(PAL_ZERO); // 4KB 메모리를 할당 (한 페이지의 크기, 파일 테이블에 1개의 페이지를 할당한다.) + if (t->fdt == NULL) { + palloc_free_page(t); + return TID_ERROR; + } + t->fd_idx = 3; + t->fdt[0] = NULL; + t->fdt[1] = NULL; + t->fdt[2] = NULL; + + + struct thread *parent = thread_current(); + list_push_back(&parent->child_list, &t->child_elem); + + /* 준비 큐에 추가. */ + /* Add to run queue. */ + thread_unblock(t); + + // 우선순위 스케줄링 + test_max_priority(); + + return tid; +} +``` + +해당 코드로 오면 중간 부분을 보면 + +```c + t->tf.rip = (uintptr_t)kernel_thread; + t->tf.R.rdi = (uint64_t)function; + t->tf.R.rsi = (uint64_t)aux; +``` + +> function == do_fork 함수 주소 +> aux == if_ 주소 + +를 넘겨주는데 rip 레지스터는 cpu가 다음으로 실행할 명령의 위치이다. 그래서 해당 스레드가 실행되면 kernel_thread라는 함수를 실행하게 되는데 그곳을 잠시보면 (threads/thread.c) + +```c +static void kernel_thread(thread_func *function, void *aux) { + ASSERT(function != NULL); + + intr_enable(); /* 스케줄러는 인터럽트를 끈 상태에서 실행됩니다. */ /* The scheduler runs with interrupts off. */ + function(aux); /* 스레드 함수를 실행합니다. */ /* Execute the thread function. */ + thread_exit(); /* function()이 반환하면 스레드를 종료합니다. */ /* If function() returns, kill the thread. */ +} +``` + +위와 같은 함수를 실행하고 보면 넘겨받은 funtion에 인자를 넣어 실행한다. 고로 해당 스레드 create이 완료되고 스케줄링되어 실행되면 do_fork(if_)를 실행하게 되는것이다!!!! + +잠시 넘어가서 thread_create아래를 더보면 fd 테이블을 할당받고 stdin, stdout, stderr를 설정해준다. + +그리고 현재 스레드의 child list에 thread_create으로 만들고 있는 스레드의 자식 요소를 넣어준다. + +> 현재 thread_create을 하고있는 스레드는 fork를 부른 스레드(부모) 이다. 해당 스레드가 자식을 낳는 과정이고 우선 생성하고 기본적인 셋팅을 해주고 나의 자식 리스트에 해당 생성할 스레드를 넣은 것이다. + +위의 과정이 끝나고 해당 스레드는 레디큐에 들어가고 스케줄링이 시작되어 언젠가 실행될것이다. + +### 위의 과정과 process_fork의 함수의 과정을 미리 말하자면. + +1. 부모 스레드가 thread_create을 통해 자식 스레드를 만들고 있다. +2. 자식 스레드에게 실행되면(눈을 뜨면) do_fork(if_)를 실행하라는 명령을 담아 레디 큐에 넣고, 부모는 자식이 실행되어 do_fork를 통해 완전히 복사가 될때까지 sema에 의해 기다린다. +3. 스케줄러에 의해 실행된 자식 스레드는 do_fork(if_) 에 의해 부모의 내용을 자기 자신에게 복사할 것이다. 복사가 실패하던 성공하던 do_fork가 끝나면 자식은 부모의 sema를 풀어준다. +4. 3번 과정이 끝나기 전까지 부모 스레드는 sema 에 의해 기다리고 있다가 3번에 의해 풀려나 자식이 온전히 생성되었는지 확인한 후 값을 반환한다. + +### 7. do_fork + +```c +static void __do_fork(void *aux) { + struct intr_frame if_; + struct thread *parent = (struct thread *) pg_round_down(aux); + struct thread *current = thread_current(); + + struct intr_frame *parent_if = (struct intr_frame *) aux; + bool succ = true; + + /* 1. CPU 컨텍스트를 로컬 스택으로 읽어옵니다. */ + /* 1. Read the cpu context to local stack. */ + memcpy(&if_, parent_if, sizeof(struct intr_frame)); + if_.R.rax = 0; + + /* 2. PT 복제 */ + /* 2. Duplicate PT */ + current->pml4 = pml4_create(); + if (current->pml4 == NULL){ + succ = false; + goto error; + } + + process_activate(current); +#ifdef VM + supplemental_page_table_init(¤t->spt); + if (!supplemental_page_table_copy(¤t->spt, &parent->spt)) { + succ = false; + goto error; + } +#else + if (!pml4_for_each(parent->pml4, duplicate_pte, parent)) { + succ = false; + goto error; + } +#endif + /* 파일 디스크립터 테이블 복제 */ + for (int fd = 0; fd < FDT_COUNT_LIMIT; fd++) { + struct file *file = parent->fdt[fd]; + if (file == NULL) + continue; + + struct file *new_file; + if (file > 2) + new_file = file_duplicate(file); + else + new_file = file; + current->fdt[fd] = new_file; + + } + current->fd_idx = parent->fd_idx; + + if (succ) + sema_up(¤t->fork_sema); + do_iret(&if_); +error: + current->exit_status = -1; + sema_up(¤t->fork_sema); + thread_exit(); +} +``` + +자식 스레드가 실행이되면 **_do_fork()** 함수를 실행하게된다 받은 **인자**는 **부모의 cpu 상태 값**들이다. + +부모 테이블의 복사를 위해 **부모 스레드 구조체 주소**를 알아내야한다. 넘겨받은 **인자 aux**는 부모 스레드 영역에 있는 주소이므로 해당 주소를 페이지 단위로 내림 (**pg_round_down**) 하면 부모 스레드의 구조체 주소가 나오게 된다. + +![](https://blog.kakaocdn.net/dn/bWfSf7/btsHpJBBL7L/sedmcUfYovvBe3H4VKHjd1/img.png) + +넘겨 받은 부모의 if_ 값을 memcpy로 do_fork내에서 선언한  if_ 에 복사해주고 자식 fork() 가 반환할 값인 0을 rax에 담아준다. 모든 과정 즉, 부모의 내용을 전부 복사하는 것에 성공했다면 부모의 세마를 풀어주고 do_iret에 방금까지 만든 if_ 값을 넣어 cpu를 **자신을 부모에게 복사한 상태와 똑같은 상태로 만들어 일을 하기 시작**한다. (부모와 똑같은 시점에 똑같은 일을 하기 시작함) + +만약, 복사가 실패했다면 자신의 종료상태를 -1로 바꿔주고 (기다리고 있던 부모가 해당 표식을 보고 자식생성 실패를 인식함!!) 부모의 세마를 풀어주고 스레드를 종료한다. + +### 8. 다시 process_fork + +```c + sema_down(&child -> fork_sema); // 자식이 메모리에 load될 때까지 기다림(blocked) + if (child -> exit_status == -1) + return TID_ERROR; + + return tid; +``` + +자식의 sema_up을 통해 다시 윗부분의 코드가 (부모) 실행된다. 부모는 자식이 제대로 생성되었는지 if 문으로 확인하고 에러 또는 자식의 tid를 반환한다. + +## 결론 + +위와 같은 긴 과정을 지나 우리의 fork 가 실행이 되었다 성공적으로 진행되었다면 + +```c +pid = fork("child"); +//부모 프로세스의 pid == 자식 tid 숫자 +//자식 프로세스의 pid == 0 +``` + +이 수행될것이다. + +fork 함수는 나와 똑같은 주소 공간과 파일을 열고있는 새로운 프로세스를 만드는 것이다. 나와 똑같지만 다른 메모리를 사용하는 (공유하기도 하지만!!) 또다른 쌍둥이를 만드는 것이고 분기가 생기는 것이다.  + +모든 것을 복사한뒤에 해당 자식을 실행할 줄 알았지만 복사하라는 명령을 쥐어 준채 실행시키는 것과 나의 (부모) 상태를 복사해야 하는데 그값은 thread 구조체의 tf가아니라 thread kernel stack 상단에 위치했다는 점이 중요했다. + +[_**pintos-kaist project 2 userprogram syscall branch 링크**_](https://github.com/JunglePintOS/pintos-kaist/tree/system-calls)    👈👈 구경오세요! \ No newline at end of file diff --git a/source/_posts/OS Project 3 WIL.md b/source/_posts/OS Project 3 WIL.md new file mode 100644 index 0000000..e43231c --- /dev/null +++ b/source/_posts/OS Project 3 WIL.md @@ -0,0 +1,111 @@ +--- +title: "OS Project 3 WIL" +date: 2024-05-21 02:53:18 +excerpt: "" + +categories: [PINTOS] +tags: [SW 사관학교 정글] +cover: /images/pintos/part3 virtual memory.jpg + +--- + +추후에 정리 +# 반효경 운영체제 가상메모리 +http://www.kocw.net/home/search/kemView.do?kemId=1046323 +https://asfirstalways.tistory.com/130 +https://product.kyobobook.co.kr/detail/S000001772604 +- Memory Management 1~4: 하드웨어가 하는 일(주소 변환, 물리메모리 관리) +- Virtual Memory 1~2: 운영체제가 하는 일(page table, io 작업) + + +## 주소 바인딩 +**logical address (=virtual address)** +- 프로세스마다 독립적으로 가지는 주소 공간 +- 각 프로세스마다 0번지부터 시작 +- **CPU가 보는 주소는 logical address임**(mmu가 변환해서 실제 메모리에서 값 가져옴) + +**Physical address** +- 메모리에 실제 올라가는 위치 + +**Symbolic address** +- 프로그래머들이 특정 이름을 통해 변수를 지정하고 값을 저장할 때, 그 변수를 하드웨어의 몇 번지에 저장할지 정하지 않는다. 또한 그 변수를 CPU가 어떻게 인식할지도 정하지 않는다. 그저 변수의 이름을 통해서 그 값에 접근할 수 있는 것이다. 그 변수를 Symbolic Address라고 한다. 이 주소가 컴파일 되어 숫자 주소가 만들어지고 이것이 물리적인 메모리와 매핑되는 것이다. 이를 주소 바인딩이라고 한다. + +## Dynamic loading, overlay +overlay가 완전 초창기 개념, +dynamic loading은 그 후에 나옴(라이브러리로 구현해서 더 편함) +실제 paing 기법의 dynamic loading과는 달른 의미에서 쓰임 + +## Dynamic Linking +실행파일과는 별도로 라이브러리를 두고 유저프로그램이 실행하다가 라이브러리 호출 부분에 라이브러리 루틴의 위치를 찾기 위한 stub이라는 작은 코드를 둔대 (해당 라이브러리가 있는 포인터) + +별도의 프로그램에 속하기 때문에 100개의 copy가 메모리에 올라감 (static) + +실행할 수 있는 라이브러리 위치코드만 두면 100명이 유저프로그램을 실행할때 메모리를 하나만 보게됨 그래서 이를 shared memory(shared object, dll)라고 함 + +## inner page table은 2^10으로 표현해야함 +2^32 프로세서에서 2단계로 페이지테이블을 표시하면 아래와 같다. +이때 왜 페이지 넘버를 2^10 두번으로 했는지 그 이유도 알아야 한다. +inner page table이나 ouuter page table이나 모두 하나의 페이지에 해당한다.(메모리에 있어야 하니) +pte는 4byte니 page table이 표현가능한 주소는 1024개다. +그러니 p2는 2^10으로 1024개를 표현해야 페이지를 전부 사용가능하다. 그래서 p2가 2^10이고 그러한 inner page table의 개수가 또 2^10(outter page table)만큼 있다. + + +그렇다면 2^64 프로세서에선? +그때는 한 페이지에 8바이트의 pte가 512개가 들어가니 inner page table을 표현하기 위해선 2^9이 필요하다. + +## 다단계 페이지 테이블 메모리 효율 안 좋아도 쓰는 이유 +다단계 페이지 테이블은 5번에 메모리 접근 필요함. 메모리 변환에 4번, 실제 메모리 접근에 1번에서 오버해드가 크다. 근데 TLB가 있으니 이러한 과정을 생략 가능. 메모리는 멀티레벨로 줄이고 시간은 TLB로 줄이고! +effective memory access time으로 설명 가능함 + +## PTE가 추가로 가지는 비트 정보 +protection이 다른 프로세스가 내 메모리 보는 그런 거 막아준다는 의미가 아님(가상메모리 그 자체가 protection을 이미 해줌) +valid는 pte가 꼭 1024개 혹은 512개 전부 존재하기 때문에 그 중에 frame에 존재하지 않는 주소는 표시해줘야함 (code, data, stack 은 다 전부 다른 page에 있음 stack은 맨 위 페이지, code는 맨 아래 페이지, 그중에 빈 페이지도 존재) + +## 페이지 폴트 처리 루틴이 운영체제에 정의되어 있다. +대부분의 경우 페이지 폴트가 안 난대 (0.98???? 교수님이 잘못 말하신듯) ~0.01래 +- 많은 데스크톱 및 서버 시스템에서 페이지 폴트율은 일반적으로 **0.1%에서 1%** 범위에 있습니다. +- 이 정도의 페이지 폴트율은 대부분의 작업에서 수용 가능하며, 성능에 큰 영향을 미치지 않습니다. +페이지폴트가 한번 나면 오버헤드가 엄청 크다. +하드웨어에서 os로 제어를 넘기는 시간(page fault handler 하기) + 필요하다면 swap page out하고 swap page in하고 다시 cpu한테 제어 넘기기 + +## swap out은 page replacement로 정한 page를 swap out함 +가능하면 페이지 폴트 안 나게, 잘 쓰는 페이지는 남겨둬야지. +페이지가 메모리에 올라오고 나서 write된적이 없다면 victim을 swap out할 필요 없이 그냥 삭제만 하면 되고 write한 적이 있다면 swap out을 해야함(백킹 storage에 저장해야 하니깐) + +swap out 및 destory되면 page table에 invalid로 표현하고 새로 swap in하는 페이지는 valid로 해야함 + +## page replacement +- optimal algorithm은 upper bound로서 다른 알고리즘의 참고용으로 쓰임 +- fifo (미래를 모르면 우선 과거부터 보자, 먼저 들어온걸 지움) +- lru (가장 오래전에 참조된건 지움) +- lfu (참조횟수가 가장 적은 페이지를 지움) + +> 캐슁에서도 이런 replacement 전략이 당연히 쓰임 + +주소변환은 하드웨어에서 하는일이므로 page table 읽어서 물리메모리 참조하는 건 cpu가 알아서 하는 일이라 운영체제가 중간에 낄 수가 없다. +page fault가 나면 disk 접근이 필요해서 트랩이 발생하고 제어권이 cpu에서 운영체제로 넘어가게된다. 그때 운영체제가 필요없는 페이지를 replacement해야하는데(ram이 가득차면) LRU, LFU를 할 수 있을까? +답은 알수가없다. 왜냐하면 페이지 폴트가 안 나면 운영체제가 하는일이 없기때문에 물리메모리 접근횟수를 운영체제가 알 수가 없다. +그러니 참조할때마다 list를 변경해줘야하는데 그걸 운영체제가 할 수 없다 (제어권이 안 넘어오므로) +buffer, web caching에서는 lru, lfu를 쓸 수 있다. 나중에 설명 + +## 그래서 사용하는 알고리즘이 Clock Algorithm +Reference bit는 하드웨어가 (이미 메모리에 존재하는 페이지를 참조하면 cpu가 해당 페이지를 읽어들이면서 1로 바꿔줌) 그걸 운영체제가 페이지 폴트시 replace해야될 상황이면 clear해주는 거지 + +read가 아니라 write로 참조도 할 수 있지. modified bit(dirty)가 0이면 replace시 그냥 destory하면 되고 1이면 disk에 반영하고 지워야함. + +## Thrashing +프로세스 하나면 IO작업할때 다른 프로세스 일 못하니 CPU 이용량이 좋지 않음 +프로세스를 늘릴수록 cpu가 쉴시간이 없이 프로세스들이 작업됨 +근데 어느 순간부터 cpu 이용량이 줄기시작하는데, 그 부분이 thrashing이 시작하는 부분임 +프로세스마다 각자 할당된 페이지가 작아서 프로세스 실행할려면 자꾸 페이지 폴트가 발생함. +그러면 io 작업이 많아지고 cpu가 쉬는 시간이 많아짐 + +그래서 동시에 올라가는 프로세스의 수를 조절해줘야함. 즉 적어도 프로그램이 어느정도는 메모리 확보할 수 있도록 보장해줘야함 그걸 해주는 알고리즘이 working-set algorithm, PFF(page-fault frequency) scheme이다. + + +# Memory Management +# Anonymous page +# Stack Growth +# Memory Mapped file +# Swap In/Out +# Copy-on-Write(Extra) \ No newline at end of file diff --git a/source/_posts/sw jungle week 0 review.md b/source/_posts/sw jungle week 0 review.md new file mode 100644 index 0000000..0e66b64 --- /dev/null +++ b/source/_posts/sw jungle week 0 review.md @@ -0,0 +1,33 @@ +--- +title: "SW 사관학교 정글 0주차 회고" +date: 2024-03-16 +excerpt: "속세와 단절된 행복한 삶" + +categories: [회고] +tags: [SW 사관학교 정글] + +--- + +카이스트 문지캠퍼스에서 오직 개발만의 삶을 살고 있다. +이런 환경을 너무 원했기 때문에 몸은 힘들지만 마음만은 풍족한 하루하루들을 보내고 있다. +2024-03-11(월)부터 지금까지 6일 간 느낀 경험에 대해 글솜씨가 부족하지만 열심히 써보겠다. + +### 시간과 몰입 +여기선 시간과 몰입을 최대치로 쓸 수 있다. +개발을 잘하는 사람들이 많고 매주 팀으로 과제를 헤쳐나가기 때문에 폐가 안될려면 최대의 몰입과 시간을 써야 한다. +체력은 자신 있기 때문에 잠부터 최대한 줄여볼 생각이다. +프로젝트가 내가 맡은 부분 때문에 망할까봐 저녁을 거르고 다음 날 아침까지 개발을 했었다. +걱정 때문에 배도 고픈지 모르고 몰입했었다. +게임할 때는 종종 밤을 샌 적이 있었지만 개발로 밤을 샌 건 처음이었다. +나도 궁지에 몰리면 할 수 있구나... 다음부턴 쉽게 포기하지 말자라고 생각했다. +프로젝트가 어느 정도 궤도에 오른 후 팀원이 사준 컵라면과 만두를 휴게실에서 먹었는데, 정말 맛있었다. + +### 자율성 +강의동, 헬스장 모두 24시간이고 정글러들은 각자 스스로 판단해서 출퇴근하면 된다. +5개월 간 몰입하면서 나만의 ritual을 만들어 갈 생각이다. +당장 하고 있는 건 자기 전 메모 및 일기 쓰는 것, 수면시간 기록하는 것뿐이다. +메모 및 일기는 생각단련을 통해 나의 주관을 갖고 싶어서이다. +수면시간 기록은 잠을 과하게 줄이는 것을 대비하기 위해 기록한다. +5개월 과정이 끝나더라도 5개월 동안 내가 얻은 좋은 습관들을 꼭 유지하고 싶다. +그래야 장기적으로 성장할 수 있는 개발자를 양성하는 sw사관학교 정글의 취지와도 맞을 것이다. +당시가 아니면 떠올릴 수 없는 생각과 감정을 최대한 기록하면서 올바른 방향으로 나아가고 싶다. diff --git a/source/images/c/1.png b/source/images/c/1.png new file mode 100644 index 0000000..392a93f Binary files /dev/null and b/source/images/c/1.png differ diff --git a/source/images/common/avatar.jpg b/source/images/common/avatar.jpg new file mode 100644 index 0000000..fd2be76 Binary files /dev/null and b/source/images/common/avatar.jpg differ diff --git a/source/images/common/favicon.jpg b/source/images/common/favicon.jpg new file mode 100644 index 0000000..7be953c Binary files /dev/null and b/source/images/common/favicon.jpg differ diff --git a/source/images/common/index_img.jpg b/source/images/common/index_img.jpg new file mode 100644 index 0000000..567384e Binary files /dev/null and b/source/images/common/index_img.jpg differ diff --git a/source/images/common/logo.png b/source/images/common/logo.png new file mode 100644 index 0000000..b6fd2da Binary files /dev/null and b/source/images/common/logo.png differ diff --git a/source/images/pintos/part1 thread.jpg b/source/images/pintos/part1 thread.jpg new file mode 100644 index 0000000..93cd3b5 Binary files /dev/null and b/source/images/pintos/part1 thread.jpg differ diff --git a/source/images/pintos/part2 user program.jpg b/source/images/pintos/part2 user program.jpg new file mode 100644 index 0000000..36e4673 Binary files /dev/null and b/source/images/pintos/part2 user program.jpg differ diff --git a/source/images/pintos/part3 virtual memory.jpg b/source/images/pintos/part3 virtual memory.jpg new file mode 100644 index 0000000..376676d Binary files /dev/null and b/source/images/pintos/part3 virtual memory.jpg differ diff --git a/source/images/pintos/part4 filesystem.jpg b/source/images/pintos/part4 filesystem.jpg new file mode 100644 index 0000000..5bfad69 Binary files /dev/null and b/source/images/pintos/part4 filesystem.jpg differ diff --git a/themes/butterfly/source/css/_page/common.styl b/themes/butterfly/source/css/_page/common.styl index 32096a5..741f902 100644 --- a/themes/butterfly/source/css/_page/common.styl +++ b/themes/butterfly/source/css/_page/common.styl @@ -8,7 +8,7 @@ flex: 1 auto margin: 0 auto padding: 40px 15px - max-width: 1200px + max-width: 1500px width: 100% +maxWidth900()