操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (2024)

系列文章目录

操作系统入门系列-MIT6.S081(操作系统)学习笔记(一)---- 操作系统介绍与接口示例
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(二)----课程实验环境搭建(wsl2+ubuntu+quem+xv6)
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities)

文章目录

  • 系列文章目录
  • 前言
  • 一、xv6文档第一章
    • 1. 引论
  • 二、实验一
    • 1.启动xv6
    • 2.实现休眠函数
    • 3.实现父子进程pingpong打印
    • 4.使用pipeline实现质数检测
    • 5.实现find函数(文件查找)
    • 6.实现xargs函数
  • 总结

前言

MIT 6.828课程资料与进度计划表
完成第一节课的学习后,按照课程的计划进度表,应当阅读xv6文档的第一章节,以及完成实验1。
本文主要内容就是对xv6文档(2023年版)和实验(2023年版)的讲解
xv6英文文档—2023
xv6中文文档—2013
xv6实验1原文

一、xv6文档第一章

1. 引论

xv6操作系统提供 Unix 操作系统中的基本接口(由 Ken Thompson 和 Dennis Ritchie 引入),同时模仿 Unix 的内部设计,包括 BSD,Linux,Mac OS X,Solaris (甚至 Microsoft Windows 在某种程度上)都有类似 Unix 的接口,理解 xv6 是理解这些操作系统的一个良好起点。
首先需要对操作系统有一个系统结构的大致概念,如下图:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (1)
如图所示,操作系统的核心就是kernel。kernel起到了桥梁的作用,连接各种应用程序和底层硬件资源。从软件编程者的角度来看,程序员就是使用各种kernel提供的系统调用函数,来实现各种各样的功能。xv6的系统调用函数如下图所示:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (2)
后面的实验就是需要调用这些系统调用函数来实现相应的功能,比如在Linux里面常用的find、xargs等命令的简易版。
在之前的文章中已经将第一章的部分进行了讲解,详情见:
操作系统入门系列-MIT6.S081(操作系统)学习笔记(一)---- 操作系统介绍与接口示例

二、实验一

1.启动xv6

详见xv6环境的配置和启动
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(二)----课程实验环境搭建(wsl2+ubuntu+quem+xv6)
(1)实验系统目录:
整个实验代码的文件目录如下,我们需要关注:

1.绿色的”grade-lab-util“可执行文件,它是测试机,用来测试你的实验代码正确性。2.kernel文件夹,是xv6的kernel代码3.Makefile是用来编译内核的,需要在这里添加参数,我们写的实验代码才能编译进去4.user文件夹是我们添加自己实验代码的地方,也就是用户空间

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (3)
(2)Makefile添加文件
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (4)
(3)退出xv6
使用”ctrl+a“,后按x退出
(4)测试机打分
需要在lab目录中添加time.txt文件,里面写一个整数,代表你的实验花了多少小时。
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (5)

2.实现休眠函数

(1)原题如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (6)
(2)大致内容为:
调用“系统调用函数——sleep()”(一次sleep()系统暂停一个tick),实现输入数字,系统暂停该数字次数的ticks。
参数错误时,要有错误打印
(3)代码如下:

// 参考echo.c、grep.c、rm.c的头文件引用#include "kernel/types.h"//声明数据类型#include "kernel/stat.h"//声明文件数据结构#include "kernel/fcntl.h"//open函数的模式参数申明#include "user/user.h"//声明各种系统调用函数、以及有用的库函数int main(int argc, char *argv[]){int number;//参数数量不对,打印错误信息//参数还有其他错误情况,此处仅考虑数量问题if(argc <= 1){fprintf(2, "usage: sleep number\n");exit(1);}number = atoi(argv[1]);//字符串转整数sleep(number);//系统调用exit(0);}

(4)结果如下:
使用官方提供的测试机程序,在lab目录下面运行"./grade-lab-util + 文件名"

./grade-lab-util sleep

测试机自主进行测试,如下图:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (7)
(5)总结:
在做实验之前我们需要知道有哪些函数我们是可以调用的,可以查看文件:“user/user.h”

struct stat;// system callsint fork(void);int exit(int) __attribute__((noreturn));int wait(int*);int pipe(int*);int write(int, const void*, int);int read(int, void*, int);int close(int);int kill(int);int exec(const char*, char**);int open(const char*, int);int mknod(const char*, short, short);int unlink(const char*);int fstat(int fd, struct stat*);int link(const char*, const char*);int mkdir(const char*);int chdir(const char*);int dup(int);int getpid(void);char* sbrk(int);int sleep(int);int uptime(void);// ulib.cint stat(const char*, struct stat*);char* strcpy(char*, const char*);void *memmove(void*, const void*, int);char* strchr(const char*, char c);int strcmp(const char*, const char*);void fprintf(int, const char*, ...);void printf(const char*, ...);char* gets(char*, int max);uint strlen(const char*);void* memset(void*, int, uint);void* malloc(uint);void free(void*);int atoi(const char*);int memcmp(const void *, const void *, uint);void *memcpy(void *, const void *, uint);

3.实现父子进程pingpong打印

(1)原题如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (8)
(2)大致内容为:
实现过程:父进程向子进程发送ping,子进程打印该信息,后子进程向父进程发送pong,父进程再打印该信息
实现结果为:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (9)

(3)代码如下:
分为单管道实现和双管道实现
单管道实现:

#include "kernel/types.h"#include "kernel/stat.h"#include "kernel/fcntl.h"#include "user/user.h"int main(int argc, char *argv[]){int p[2];char buf[512];//用来接收信息的bufferpipe(p);//父 <=======> 子//子进程执行if,父进程执行elseif(fork() == 0){read(p[0], buf, sizeof(buf));//阻塞,直到父进程写入管道p内容,后读取父进程的信息fprintf(1,"%d: received %s\n", getpid(), buf);//打印父进程的信息write(p[1], "pong", 5);//使用p的写通道向父进程发送信息close(p[0]);//关闭读通道close(p[1]);//关闭写通道exit(0);//子进程退出}else{write(p[1], "ping", 5);//父进程通过p的写通道向子进程发送信息wait((int *)0);//等待子进程结束read(p[0], buf, sizeof(buf));//读取p管道中子进程的信息fprintf(1,"%d: received %s\n", getpid(), buf);//打印子进程的信息close(p[0]);//关闭读通道close(p[1]);//关闭写通道}exit(0);}

双管道实现:

#include "kernel/types.h"#include "kernel/stat.h"#include "kernel/fcntl.h"#include "user/user.h"int main(int argc, char *argv[]){int p[2];int p2[2];char buf[512];//用来接收信息的buffer//向内核申请两个管道pipe(p);//父进程写,子进程读:父 ——————> 子pipe(p2);//子进程写,父进程读:子 ——————> 父//子进程执行if,父进程执行elseif(fork() == 0){close(p[1]);//关闭p的写通道,以便于父进程写完可以直接读取read(p[0], buf, sizeof(buf));//阻塞,直到父进程写入管道p内容,后读取父进程的信息fprintf(1,"%d: received %s\n", getpid(), buf);//打印父进程的信息close(p[0]);//关闭p的读通道write(p2[1], "pong", 5);//使用p2的写通道向父进程发送信息close(p2[1]);//写完关闭写通道close(p2[0]);//关闭p2的读通道exit(0);//子进程退出}else{write(p[1], "ping", 5);//父进程通过p的写通道向子进程发送信息close(p[1]);//写完关闭写通道close(p2[1]);//关闭p2的写通道,以便于子进程写完可以直接读取read(p2[0], buf, sizeof(buf));//阻塞,直到子进程写入管道p2内容,读取子进程的信息fprintf(1,"%d: received %s\n", getpid(), buf);//打印子进程的信息close(p[0]);//关闭p的读通道close(p2[0]);//关闭p2的读通道}exit(0);//结束程序}

(4)结果如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (10)
(5)总结:

4.使用pipeline实现质数检测

(1)原题如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (11)
(2)大致内容为:
使用pipeline+多进程来检测35以内的质数检测
这个过程比较难想,但是在纸上推演一下流程就懂了,参考文献如下:Bell Labs and CSP Threads

参考伪代码:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (12)
参考图:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (13)
(3)代码如下:

#include "kernel/types.h"#include "kernel/stat.h"#include "kernel/fcntl.h"#include "user/user.h"void child(int * p){int p1[2];char num[35];int prime;int i;int ret;int number;pipe(p1);close(p[1]);number = 0;for(i=0;i<35;i++){ret = read(p[0], num+i, 1);if(ret == 0){break;}number++;}if(number == 0){exit(0);}prime = num[0];printf("prime %d\n", prime);close(p[0]);if(fork() == 0){child(p1);}else{close(p1[0]);for(i=1;i<number;i++){if((num[i]%prime)!=0){write(p1[1], num+i, 1);}}close(p1[1]);wait((int *)0);}exit(0);}int main(){int prime = 2;int p[2];int i;pipe(p);if(fork() == 0){child(p);}else{close(p[0]);printf("prime %d\n", prime);for(i=3;i<=35;i++){if((i%prime)!=0){write(p[1], &i, 1);}}close(p[1]);wait((int *)0);}exit(0);}

(4)结果如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (14)
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (15)
(5)总结:
核心是算法题,载体是进程树之间使用pipeline进行读写控制

5.实现find函数(文件查找)

(1)原题如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (16)
(2)大致内容为:
实现目录下搜索文件的功能,要求能够找到该文件夹目录下以及其子目录下的指定文件名,输出所有满足文件的路径。(不要求实现正则表达式)(!!!记得规避".“与”…"子文件)(如何访问文件夹可以参考文件ls.c的实现)

 " . " 表示当前目录" .. " 表示当前目录的上一级目录。" ./ " 表示当前目录下的某个文件或文件夹,视后面跟着的名字而定" ../ " 表示当前目录上一级目录的文件或文件夹,视后面跟着的名字而定。

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (17)
(3)代码如下:

#include "kernel/types.h"#include "kernel/stat.h"#include "kernel/fcntl.h"#include "kernel/fs.h"#include "user/user.h"char* fmtname(char *path){char *p;// Find first character after last slash.for(p=path+strlen(path); p >= path && *p != '/'; p--);p++;return p;}int find(char *name, char *p){int fd;int path=0;char buf[512];struct dirent de;struct stat st;fd = open(p, O_RDONLY);if(fd < 0){fprintf(2, "fd: can not open %s\n");exit(1);}strcpy(buf, p);p = buf+strlen(buf);*p++ = '/';// printf("%d %s\n", fd, buf);while(read(fd, &de, sizeof(de)) == sizeof(de)){if(de.inum == 0){continue;}memmove(p, de.name, DIRSIZ);p[DIRSIZ] = 0;// printf("%s\n", p);if(stat(buf, &st) < 0){printf("ls: cannot stat %s\n", buf);continue;}// printf("%s %s %d\n", buf, fmtname(buf), st.type);// printf("%d %d %d\n", strcmp(fmtname(buf), name), strcmp(fmtname(buf), "."), strcmp(".", "."));if (st.type == T_FILE && (strcmp(fmtname(buf), name) == 0)){printf("%s\n", buf);path = 1;} if (st.type == T_DIR && (strcmp(fmtname(buf), ".") != 0) && (strcmp(fmtname(buf), "..") != 0)){path = find(name, buf);} }return path;}int main(int argc, char *argv[]){int path;if(argc < 3){fprintf(2, "fd: find [dir] [filename]\n");exit(1);}path = find(argv[2], argv[1]);if(path == 0){fprintf(1, "can not find such file\n");}exit(0);}

(4)结果如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (18)
(5)总结:
核心知识点是xv6系统下的文件结构体与文件夹结构体,使用递归方法进行实现。

6.实现xargs函数

(1)原题如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (19)
(2)大致内容为:
实现xargs命令,xargs命令很难简单理解,建议先查一下命令的用法。
xargs 命令教程
(3)代码如下:

#include "kernel/types.h"#include "kernel/stat.h"#include "kernel/fcntl.h"#include "user/user.h"#include "kernel/param.h"int getcmd(char *buf, char**arg, int arg_num){int i;int j;j = 0;arg[arg_num] = (char *)malloc(30 * sizeof(char));for(i=0; i<512; i++){if((buf[i] == ' ') || (buf[i] == 10) || (buf[i] == '\0') || (buf[i] == '\n')){// printf("%c %d\n", buf[i], buf[i]);arg_num++;if(buf[i] == 10){// printf("argmun: %d\n", arg_num);return arg_num;}if(buf[i] == '\0'){// printf("argmun: %d\n", arg_num);return arg_num;}arg[arg_num] = (char *)malloc(30 * sizeof(char));// printf("111\n");// printf("%s %p kkk\n", arg[arg_num], arg[arg_num]);j = 0;}else{// printf("%d %d %c %d\n", j, i, buf[i], arg[arg_num][j]);arg[arg_num][j] = buf[i];// printf("%d %c \n", j, arg[arg_num][j]);j++;}}return arg_num;}int main(int argc, char *argv[]){char buf[512];int num = 0;int ret;int cmd = 0;char *arg[MAXARG];int arg_num;arg_num = argc - 1;int i = 0;for(i=0; i<arg_num; i++){arg[i] = argv[i+1];}if(argc < 2){fprintf(2, "xarg: xarg [process] [args...]\n");exit(1);}int j = 0;while(1){ret = read(0, buf+j, 1);if(ret != 1){break;}else if(buf[j] == '\n'){// printf("read number is : %d\n%s\n", num, buf);j = 0;num = 0;cmd = getcmd(buf, arg, arg_num);// printf("\n\n%d %d\n", cmd, arg_num);// printf("%s\n%s\n%s\n%s\n", arg[0], arg[1], arg[2], arg[3]);if(cmd == arg_num){printf("%d %d\n", cmd, arg_num);printf("no content of stdin\n");}else{if(fork() == 0){exec(argv[1], arg);fprintf(2, "exec failed\n");exit(1);}else{wait((int *)0);}}}else{j++;num++;}}for(i=0; i<cmd; i++){free(arg[i]);}exit(0);}

(4)结果如下:
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (20)
(5)总结:
在实现字符串的单词分割的时候,对于指针的操作出现问题。
char **arg的arg[]元素应该动态分配空间,而不是讲temp数组的指针头直接赋值。

总结

课程每年可能有变化,本文按照最新的2023计划表进行学习

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (21)

【全开源】防伪溯源一体化管理系统源码(FastAdmin+ThinkPHP+Uniapp)

&#x1f50d;防伪溯源一体化管理系统&#xff1a;守护品质&#xff0c;追溯无忧 一款基于FastAdminThinkPHP和Uniapp进行开发的多平台&#xff08;微信小程序、H5网页&#xff09;溯源、防伪、管理一体化独立系统&#xff0c;拥有强大的防伪码和溯源码双码生成功能&#xff0…...

编程日记2024/6/9 18:24:21

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (22)

matplotlib 动态显示训练过程中的数据和模型的决策边界

文章目录 Github官网文档简介动态显示训练过程中的数据和模型的决策边界安装源码 Github https://github.com/matplotlib/matplotlib 官网 https://matplotlib.org/stable/ 文档 https://matplotlib.org/stable/api/index.html 简介 matplotlib 是 Python 中最常用的绘图…...

编程日记2024/6/9 18:00:05

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (23)

WPF音乐播放器 零基础4个小时左右

前言&#xff1a;winfrom转wpf用久的熟手说得最多的是,转回去做winfrom难。。当时不明白。。做一个就知道了。 WPF音乐播放器 入口主程序 FontFamily"Microsoft YaHei" FontSize"12" FontWeight"ExtraLight"居中显示WindowStartupLocation&quo…...

编程日记2024/6/9 15:38:38

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (24)

vue3模板语法总结

1. 响应式数据 Vue 3中的数据是响应式的&#xff0c;即当数据发生变化时&#xff0c;视图会自动更新。这是通过使用JavaScript的getter和setter来实现的。 2. 组件化 Vue 3采用组件化开发方式&#xff0c;允许创建可复用的组件。 每个组件都有自己的作用域&#xff0c;并且…...

编程日记2024/6/9 13:11:19

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (25)

Redis事务和Lua脚本:扩展功能与性能优化

一、Redis事务介绍 A. 事务的定义: Redis的事务是一系列命令的集合,这些命令将被序列化并顺序执行。事务在执行过程中保持原子性,即事务中的命令要么全部执行,要么全部不执行。Redis为了保证事务的执行不被其他命令请求中断,确保了事务命令序列在执行时的独立性。 B. 事…...

编程日记2024/6/9 11:16:12

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (26)

Unreal Engine项目结构与关卡设置详解

引言 Unreal Engine 是一款功能强大的游戏引擎&#xff0c;为开发者提供了丰富的工具来创建和管理游戏项目。本文将详细介绍一个基本的 Unreal Engine 项目结构&#xff0c;并讲解如何在 Unreal 编辑器中进行关卡设置与操作。 Unreal Engine 项目结构 一个基本的 Unreal Eng…...

编程日记2024/6/9 9:47:20

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (27)

jenkins集成

jenkins是一款广泛使用的开源持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;工具&#xff0c;主要用于自动化构建、测试和部署软件。以下是关于如何集成Jenkins的详细介绍&#xff1a; 安装Jenkins&#xff1a; 要安装Jenkins&#xff0c;您需要按照…...

编程日记2024/6/9 17:20:10

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (28)

(超详细)字符函数和字符串函数【上】

前言 C 语言中对字符和字符串的处理很是频繁&#xff0c;但是 C 语言本身是没有字符串类型的&#xff0c;字符串通常放在 常量字符串 中或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数 . 1.求字符串长度函数 strlen函数 我们要求一个字符串函数的长度…...

编程日记2024/6/9 17:22:14

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (29)

Instagram运营必备工具合集

Instagram的运营不仅仅涉及数据分析&#xff0c;还包括内容规划、发布管理、互动提升和广告优化等多个方面。以下是一些海外社媒Instagram运营必备的工具&#xff0c;这些工具可以帮助您更有效地管理和提升您的Instagram账号。 Instagram 运营必备工具合集 数据分析工具 1、Ins…...

编程日记2024/6/8 21:17:54

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (30)

linux学习(六)

1.网络管理 (1)查看 ifconfig: root用户可以查看网卡状态, 普通用户: /sbin/ifconfig(需要加上命令的完整路径) (2)修改网络配置 通过命令修改网络配置 设置网卡的ip地址;禁用网卡和启用网卡了。 添加网关: (3)网络故障查询 ①ping 检测当前主机和目标主机是…...

编程日记2024/6/8 21:41:58

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (31)

软考结束。有什么要说的

1. 竟然是机试&#xff0c;出乎我意料。是 考试机构觉得笔试成本高了么。这次的考试是机试&#xff0c;相比以往有所不一样。感言是不是以后都会在固定地点考试也说不准。 2. 遇到年轻人。 这次旁边的一个女同学第一次参加&#xff0c;还像我询问了一些关于软考的事。我是有…...

编程日记2024/6/9 16:53:50

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (32)

十分钟精通MinIO:minio的原理、部署、操作

一、认识MinIO Minio是一个简单易用的云存储服务&#xff0c;就像是一个放在网络上的大文件柜。想象一下&#xff0c;你有一间放满了各种文件的房间&#xff0c;有时候你需要把这些文件分享给朋友或者在不同地方访问它们。Minio就是帮你做到这一点的工具&#xff0c;它让你可以…...

编程日记2024/6/4 10:36:05

操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities) (2024)

References

Top Articles
Latest Posts
Article information

Author: Dong Thiel

Last Updated:

Views: 6747

Rating: 4.9 / 5 (79 voted)

Reviews: 86% of readers found this page helpful

Author information

Name: Dong Thiel

Birthday: 2001-07-14

Address: 2865 Kasha Unions, West Corrinne, AK 05708-1071

Phone: +3512198379449

Job: Design Planner

Hobby: Graffiti, Foreign language learning, Gambling, Metalworking, Rowing, Sculling, Sewing

Introduction: My name is Dong Thiel, I am a brainy, happy, tasty, lively, splendid, talented, cooperative person who loves writing and wants to share my knowledge and understanding with you.