2014年9月28日

在Mac上編譯 tesseract 3.03

在Mac上沒有提供直接執行的binary

port 指令也只找到3.02版

3.03版才開始有training功能

如要使用就要透過編譯 source 的方式安裝

首先必須要在appStore安裝 xcode

之後先啟動一次xcode,按下Agree

才會有完整的compiler



編譯 leptonica 1.71


在編譯 tesseract 之前需要先有這個東西

而編譯 leptonica 之前又必須要先有各種圖片 lib

所以先用port 安裝

#sudo port install jpeg tiff libpng

再去官方網站下載 leptonica source

http://www.leptonica.com/download.html

解壓縮之後進入目錄裡

輸入

#./configure LDFLAGS=-L/opt/local/lib/ CFLAGS=-I/opt/local/include/

再來就是 make && sudo make install


編譯tesseract 3.03

利用 git 指令下載source

git clone https://code.google.com/p/tesseract-ocr/

若要用到 training 功能

就要另外安裝幾個套件

sudo port install pango

sudo port install cairo

以我當時情況只缺這兩個而已

每檯主機情況不同

若不知道自己缺什麼

就先執行 

./autogen.sh

./configure

仔細查看 output 訊息

安裝漏掉的 lib

都安裝完之後就

執行

#./autogen.sh
#./confugure
#make
#sudo make install

編譯 training 工具

#make training
#sudo make training-install

language data 我是先用 3.02的

可在

https://code.google.com/p/tesseract-ocr/downloads/list

下載

將language files 複製到 /usr/local/share/tessdata/ 下

之後就可以用

#tesseract imagefile output_file_name

做圖片辨識

2014年8月27日

在CentOS 7 / 6 / 5 安裝Nginx, PHP5.5.x, MariaDB

基本上是翻譯這篇:

http://www.if-not-true-then-false.com/2011/install-nginx-php-fpm-on-fedora-centos-red-hat-rhel/

加上一些我個人實裝記錄

此篇以CentOS 7 為主要OS


安裝


首先先安裝第三方Repo

## Remi Dependency on CentOS 7 and Red Hat (RHEL) 7 ##
rpm -Uvh http://dl.fedoraproject.org/pub/epel/beta/7/x86_64/epel-release-7-0.2.noarch.rpm
 
## CentOS 7 and Red Hat (RHEL) 7 ##
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

並編輯(產生) /etc/yum.repo.d/nginx.repo

內容如下:

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
之後就下指令安裝nginx, php-fpm, php


yum --enablerepo=remi,remi-php55 install nginx php-fpm php-common

然後再安裝PHP會用到的module

yum --enablerepo=remi,remi-php55 install php-opcache php-pecl-apcu php-cli php-pear php-pdo php-mysqlnd php-pgsql php-pecl-mongo php-sqlite php-pecl-memcache php-pecl-memcached php-gd php-mbstring php-mcrypt php-xml
我有再另外增加 php-intl



在CentOS 7

啟動service的方式已經不同

之前都是 /etc/init.d/xxx start

來啟動

現在變成要透過 systemctl 的指令

#systemctl start nginx.service

#systemctl start php-fpm.service

手動啟動nginx與php-fpm之後

應該就可以在瀏覽器看到nginx歡迎頁面了




ps. 本機IP為 127.0.0.1 或使用 ifconfig 查看當前 ip
       若無法瀏覽可使用 #systemctl status nginx.service 查看啟動狀態
       或是 #netstat -nulpt 指令查看是否有開啟80 port
       若都正常可嘗試暫時清除iptable的規則 #iptables -F
       或是暫時關閉 SELinux ,#setenforce 0



成功後就可以加入開機自動啟動了

systemctl enable nginx.service
systemctl enable php-fpm.service

Nginx設定


接下來就沒有完全依照網站上的步驟

但都大致相同

首先要先設定Nginx的Virtual Host

建立多網站資料夾

#mkdir /srv/www
#mkdir /srv/www/sites
#mkdir /srv/www/sites/test
#mkdir /srv/www/logs
#mkdir /srv/www/logs/test

修改權限

#chown -R apache:apache /srv/www
#chown -R nginx:nginx /srv/www/logs

這邊要注意的是,我把www整個資料夾擁有者指定給apache

是因為php-fpm預設使用apache的user & group解析(執行)php

如果要指定成別的user:group 就要記得修改 /etc/php-fpm.d/www.conf

最後也另外指定logs資料夾給nginx


之後在/etc/nginx新增兩個資料夾

#mkdir /etc/nginx/sites-available
#mkdir /etc/nginx/sites-enabled

修改 /etc/nginx/nginx.conf


include /etc/nginx/conf.d/*.conf;
下面增加


## Load virtual host conf files. ##
include /etc/nginx/sites-enabled/*;
並且在sites-available新增一個Virtual Host config

#vim /etc/nginx/sites-available/test_site

內容為

server {
    server_name YOUR_SERVER_NAME;
    access_log /srv/www/logs/test/access.log;
    error_log /srv/www/logs/test/error.log;
    root /srv/www/sites/test;
 
    location / {
        index index.html index.htm index.php;
    }
 
    location ~ \.php$ {
        include /etc/nginx/fastcgi_params;
        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /srv/www/sites/test$fastcgi_script_name;
    }
}
之後在 sites-enabled 資料夾產生 soft link

cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/test_site

並且重新啟動 nginx

#systemctl restart nginx.service

最後在根目錄下產生一個測試的php檔案

vim /srv/www/sites/test/index.php

內容為

<?php

phpinfo();

這時再重新整理

應該就可以看見phpinfo的內容

如果出現Error 403

那要設定一下SELinux

chcon -R -t httpd_sys_content_t /srv/www/sites/test
 
## Or some apps might need httpd_sys_rw_content_t ##
chcon -R -t httpd_sys_rw_content_t /srv/www/sites/test

設定 iptables 

在 CentOS 7 已經無法像之前一樣

直接修改 /etc/sysconfig/iptables

真是不太方便

而且要用一個沒用過的指令

firewall-cmd

firewall-cmd --permanent --zone=public --add-service=http
 
## OR ##
 
firewall-cmd --permanent --zone=public --add --port=80/tcp
我是用

#firewall-cmd --permanent --zone=public --add-port=80/tcp

之後再重新啟動 iptable

#systemctl restart firewalld.service

這樣就大功告成摟!


安裝 MariaDB


安裝
#yum install mariadb mariadb-server

啟動
#systemctl start mariadb.service

開機啟動
#systemctl enable mariadb.service

執行MySQL安全設定script
#/usr/bin/mysql_secure_installation

過程如下所示


NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!
 
In order to log into MariaDB to secure it, we\'ll need the current
password for the root user.  If you\'ve just installed MariaDB, and
you haven\'t set the root password yet, the password will be blank,
so you should just press enter here.
 
Enter current password for root (enter for none): 
OK, successfully used password, moving on...
 
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.
 
Set root password? [Y/n] y
New password: 
Re-enter new password: 
Password updated successfully!
Reloading privilege tables..
 ... Success!
 
 
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.
 
Remove anonymous users? [Y/n] y
 ... Success!
 
Normally, root should only be allowed to connect from \'localhost\'.  This
ensures that someone cannot guess at the root password from the network.
 
Disallow root login remotely? [Y/n] y
 ... Success!
 
By default, MariaDB comes with a database named \'test\' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.
 
Remove test database and access to it? [Y/n] y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!
 
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
 
Reload privilege tables now? [Y/n] y
 ... Success!
 
Cleaning up...
 
All done!  If you\'ve completed all of the above steps, your MariaDB
installation should now be secure.
 
Thanks for using MariaDB!

另一個重點是

程式用的帳號都要另外創建

而且權限只能使用某個DB

除非有用cluster或要跟其他DB sync

才要設定 Listen port 3306 on Internet

不然就都 Listen localhost





2014年5月5日

PHP Framework 該如何選



對於一個寫了很久PHP的人來說

都會想找尋更好的方法

在五六年前,PHP Framework還不盛行的時候

只能由自己硬幹出很多的class 來resue

但在這個Framework爆炸的時代

就別再這麼辛苦了



Framework的選擇



其實還是要以自己的需求為主

像我這麼懶惰的人

就是不希望寫太多code

就能做到很多事

這時候就只能朝Full-stack的framework來選

例如像是:Symfony2, Laravel, Yii等

這一類的framework的優點是

套件多,功能多,包裝多,有一定的規範

在團隊合作時不會因為A喜歡這樣寫B喜歡那樣寫

整份project就充斥著不同的風格與寫法

但是有些人因為喜歡PHP的自由風氣

所以不想被這麼多規範給框住

或是只是想寫個留言板而已

幹嘛大費周章用這麼肥大的Full-stack framework?

這時就會想選輕量化的framework

像是CodeIgniter, Silex, Slim


framework 並沒有一定的好跟壞

全看自己的需求與想法來決定

如果要功能齊全,寫起來舒服覺得爽

被改需求也不會感到痛苦

並且想快速推出產品的話

Full-stack framework絕對是首選

如果要風格自由,要比較快

輕量化framework就是首選了

不過以現今趨勢來說

都是以Full-stack framework在猛烈成長

像是參考 Best PHP Frameworks for 2014 這篇文章來說

前幾名的都是Full-stack framework

還有很紅的Ruby on Rails也是

這似乎是一個趨勢啊

(大概大家都很懶的關係XDD)

2014年5月2日

CentOS SSH 時無法使用 su 換成root

今天突然無法用su -切換成root

以為被入侵入改了密碼

大老遠跑來server旁邊

竟然可以在local端登入

最後檢查/bin/su權限

發現是

-rwxr-xr-x.

才發現權限不對

估計是昨晚不知下了哪個指令給改了....

之後下

chmod u+s /bin/su

給改了回去

才正常。

2014年5月1日

讓SELinux可以透過httpd(PHP)寄信

SELinux開啟時

預設是無法直接由網站寄信的

可以先查看設定值


getsebool httpd_can_sendmail

一開始都是 off

然後

setsebool -P httpd_can_sendmail 1


chcon -t httpd_sys_content_t /usr/sbin/sendmail.postfix 

就可以透過網站(PHP)送信了

必要時可檢查與恢復postfix相關權限

# /etc/init.d/postfix stop
# chgrp postdrop /usr/sbin/postqueue
# chgrp postdrop /usr/sbin/postdrop
# chmod g+s /usr/sbin/postqueue
# chmod g+s /usr/sbin/postdrop
# /etc/init.d/postfix start

2013年9月18日

Symfony2 initial project ICU problem

今天在初始化Symfony2時

在Terminal下

$php composer.phar instal

卻出現一串錯誤

Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for symfony/icu v1.2.0 -> satisfiable by symfony/icu[v1.2.0].
    - symfony/icu v1.2.0 requires lib-icu >=4.4 -> the requested linked library icu has the wrong version installed or is missing from your system, make sure to have the extension providing it.
  Problem 2
    - symfony/icu v1.2.0 requires lib-icu >=4.4 -> the requested linked library icu has the wrong version installed or is missing from your system, make sure to have the extension providing it.
    - symfony/symfony v2.3.4 requires symfony/icu ~1.0 -> satisfiable by symfony/icu[v1.2.0].
    - Installation request for symfony/symfony v2.3.4 -> satisfiable by symfony/symfony[v2.3.4].

最後弄很久

選擇怒關ICU功能

$php composer.phar require symfony/icu ~1.0

之後就正常了

2012年12月6日

How to hide the Apache version information in http header

edit the /etc/httpd/conf/httpd.conf file ( in Ubuntu server is /etc/apache2/apache2.conf )

and add

ServerTokens ProductOnly
ServerSignature Off

or edit if the option exist.

ServerTokens options and results:


ServerTokens ProductOnly

result:
Server: Apache

ServerTokens Major

result:
Server: Apache/2

ServerTokens Minor

result:
Server: Apache/2.0

ServerTokens Minimal

result:
Server: Apache/2.0.55

ServerTokens OS

result:
Server: Apache/2.0.55 (Debian)

ServerTokens Full (or not specified) default

result:
Server: Apache/2.0.55 (Debian) PHP/5.1.2-1+b1 mod_ssl/2.0.55 OpenSSL/0.9.8b


and hide the php information

edit /etc/php.ini

edit expose_php to Off

( expose_php = Off )

2012年11月16日

Amazon RedHat Instance ssh login


ssh -i /your/pem/path/file.pem root@ec2-xxxxx-1.ap-northeast-1.compute.amazonaws.com

use root...not ec2-user

>_<

2012年5月16日

HTC - 三星 - 蘋果




其實我完全不知道標題該怎麼下...

在此分享一篇文章

鴻海、宏達電  誰對台灣更重要?
http://www.cw.com.tw/article/article.action?id=5032848

我對財經是完全的門外漢
所以無法求證或給大家保證裡面數字都是對的
但商業週刊裡的文章應該不會離譜到哪

如果裡面所言屬實
我們是否該思考一下
買三星、蘋果的手機
會造成什麼樣的後果?

原本我也是半信半疑,愛用國貨有差這麼多嗎?
哪可能因為我一個人不買,明天台灣就垮掉了
但從這些現象看起來
還真的有可能...

撇開政治因素
HTC也為台灣帶來不少好處(這樣講應該對吧?肚子裡沒裝太多專有名詞XDD)
如果繼續助長三星、蘋果的勢氣
那真的只能說
『歡喜做,甘願受』
別怪薪水只有22k,也別怪薪水20年沒漲了....


我也不是在強迫大家要買哪家的產品
相信蘋果、三星這兩家廠商有各自的優點
才會吸引大批"粉絲"擁戴
這絕對是我們該學習的
但是選擇的當下
應該可以有另一種不一樣的思維來看待這件事!

2012年5月4日

為什麼我會買iPhone?



蘋果給大眾的印象就是,封閉、不自由、會被洗腦、盲從
半年前,我也還是一個很討厭Apple這字眼的科技人。

從 iPod 盛行的年代開始,我就一直視蘋果為非必要買進的科技產品
加上發現大部分拿Apple的人都有幾個特色
就是覺得這樣很潮、跟得上流行、買了產品,但卻不知道買來要幹嘛(很多人都喜歡在螢幕上滑來滑去,但其實我永遠不知道他們在滑什麼..........)
並且自從Android出來之後更會大肆批評其他品牌
這現象令人從心底討厭這產品

2011年 Steve Jobs 去世,眾多人為他悼念
當時的我純粹抱著死者為大的心態,祝福他離開這人世間
也慢慢接觸到他的傳記、演講、產品發表會...等等,有關於他的一切
發現他是一個很特別的人,他的人生也經歷各種起伏
他從Apple被趕出來到重新回去的那段,最能鼓舞我的心
也驗證了有失敗,就一定會有成功,這是個相對的世界。

那時,我便開始思考
如果一個產品很爛,有可能會出現這麼多支持者嗎?
難道賈伯斯以前是學催眠的嗎?
到底是什麼吸引了這麼多粉絲?
所謂的粉絲其實也是人,應該說到底是什麼吸引了那麼多人?
這些人還很愛用,聽說用了就不會想再換,很快就會變成忠實客戶

帶著這些好奇,我選擇用 iPhone 進入這神祕的世界
而他帶給我的感受
是使用了三 四年Android的我所無法想像的
的確,這是我們科技人所缺乏的設計感
的確,程式寫多了,腦子裡只剩下if then else的邏輯
一直到了現在,雖然我也有Android手機
但早就把主要使用的手機轉移到了 iPhone 上。


這世界很大
如果我們用拒絕的心看某一件事或某個角落
那我們就少接觸了另一種感觸
眼界就變得相對渺小了
不要小看這世界任何一個產品
就像Dropbox剛出來時我也覺得這沒什麼
只要寫過程式的人都會有類似的東西
但它的思維和我們寫程式的人不一樣
他就是要做給不會寫程式的人用的
所以不只在程式上下功夫
更是用心打造、包裝"產品"
如果我們早點學會開放自己的心
我們就能早點在這些發光發熱的產品上學習
而不是一直活在自己的世界

btw, 其實很多人討厭蘋果,都跟我一樣討厭的是"人",如果是這樣,那我會誠心的建議你去體驗一下蘋果的產品,但記住別變成自己曾經討厭的"人"。

2012年4月29日

創業的目的



http://mrjamie.cc/2012/04/30/phil-libin/

這篇文章真的寫得太好了
也讓我之前的疑惑有了解答

雖然文章裡說台灣為了錢創業的現象還好
但我身邊的人很多想創業都是為了錢

舉例來說
有參加過直銷說明會的人應該都知道
他們一貫的說法就是
這裡不是直銷,是在經營一個自己的事業!!
賺不賺錢,純看你的努力!!
有人可以月入十幾萬!!你一定也可以!!
結果就因為那句月入十幾萬就當了別人的下線
還沒月入十萬就先花了十幾萬幫人衝業績

這是一個很畸形的例子
因為這根本不是一個創業的行為
這就只是讓你跳進慾望的坑洞裡
讓妳為了錢賣命
最後一無所獲
甚至只會怪自己不夠努力才沒有收穫


如果是為了錢,Please DON'T do it.
好好當員工,領月薪,學會理財
可能還會賺得更多。

2012年4月26日

【JavaScript】Closure in for loop



我們通常會遇到以下情況

假設有個簡單網頁,所包含的元件如下

<ul>
    <li>123</li>
    <li>456</li>
</ul>

我們要給每個 li 加上一個 onclick 事件

滑鼠點擊後會 alert 順序的編號

為了讓程式聰明點

我們通常會使用 getElementsByTagName

和 foor loop 來 add event

例如:


var list = document.getElementsByTagName("li");
for( var i=0; i<list.length; i++){
list[i].onclick = function(){
alert(i);
}
}

但是這樣會發現一個嚴重的問題

每個 li alert的數字都一樣是2

為什麼?

因為當滑鼠按下時,做的動作是: alert(i);

而當時的 i 早就跑完迴圈變成 2 了

所以應該要這樣寫:


var list = document.getElementsByTagName("li");
for( var i=0; i<list.length; i++){
list[i].onclick = (function(index){
return function(){
alert(index);
}
})(i);
}

把重要的那部分拿出來研究一下:


        (function(index){
return function(){
alert(index);
}
})(i)

最外面的 ()(i) 的意思是執行裡面的 anonymous function

而裡面的 anonymous function 又 return 一個 function

return 的 function 做的事情是 alert(index)

index 又是  anonymous function 的 parameter

就是一個不被外部干擾的 Local variable

所以可以保證 alert 是我們想要的數字


一個看似成功的"手機"平台:Android


隱約記得,在我大三那年
我們學長就在玩著一堆Bug的Android
我還拿著我的Sony Ericsson K810i
只有試玩過那時候破爛破爛的windows mobile
當時對智慧型手機的看法就是:爛

一直到了去年
Android 修掉了大部分的Bug
把使用者感覺的到的問題都修正了
一切看起來很美好
到了Android 4.0 更是對UI做了大幅度的改進
但是Android隱藏的怪物
卻始終在那

不過說是怪物
不如說Android就是靠這賺錢的
如果這篇文章在2010或2011初的時候寫
我還可以大肆批評Android架構如何爛如何差(但其實我並不善於批評XD)
而且可能只有我或少數人能認同
(其實去年我在跟我身邊朋友討論時,多數人都不相信我說的)
到了2012年,我終於敢寫這篇文章了

因為這世界上,不再只有我這樣想
先來引述幾篇文章

2012-02-07
七種跡象表明,Android將被強勢的iOS拽出疾速增長的軌道
http://www.36kr.com/p/81192.html

這篇文章可能是我所看到的第一篇,敢跳出來戰Android的文章
當時下面的回覆可是熱鬧非凡(不過改版後回復都不見了?)
我當然也有跳進去湊熱鬧XD
在今年2月的時候
仍然有大多數人看好Android,不斷吐槽寫這篇文章的人

不過在短短兩個月內!!
是的,就是今年四月
2012-04-22
實時研究表明:相比於Android,iOS設備用戶活躍度佔絕對主導地位
http://www.36kr.com/p/102211.html

這結果我並不意外
比較讓我意外的是下面的回覆
竟然大多數人都贊同這篇文章的研究結果!

自此之後,不利於Android文章越來越多

2008年以來Google通過Android只撈到5.5億美元,通過iPhone收入達數十億
http://www.36kr.com/p/95345.html
Android:什麼情況?
http://www.36kr.com/p/103038.html
單個應用上每用戶貢獻平均收入,Amazon 大於iTunes,並遠超Google Play
http://www.36kr.com/p/103380.html
212-04-27
左有蘋果的 iPhone,右有 Amazon 的 Kindle Fire,Google 的 Andr​​oid 將走向何方
http://techorange.com/2012/04/27/where-should-google-go-with-android/

到底是什麼原因造成現在的局面?

就我所觀察
比較嚴重的有兩點(但都跟Android架構無關XDD)
1. 版本分裂,導致開發者開發Android App時難度增加
我想最常聽見的就是,要為了每種不同解析度的螢幕優化
實在快累死人~~
不過這種情況在Android 4.0被稍稍改善
但由於4.0市占率不高,加上有消息稱5.0就快發布了
我想這問題還會持續好一陣子。

2. Android App太容易複製、傳播
這應該就是嚴重影響,Google Play 上使用者付費意願的主要原因
大家應該都知道SPB Mobile Shell,一個很華麗的桌面應用程式
Google Play上定價快500台幣
在Android 世界裡,算是賣得不錯
但很不幸的,只要在google搜尋欄位輸入"spb mobile shell 5.0 破解"
還真的就找到免費完整版了...
更不用說其他軟體了

不過有人會說 iPhone 越獄後不也一樣嗎?
根據個人使用經驗
我用過Hero, Desire(都是老牌的了XD),一隻iPhone 3GS
Android刷機是一定要的,iPhone越獄也是必然的
就我體驗的結果是
我的iPhone雖然越獄了
但Cydia的搜尋功能真是爛的可以...
而且除非我知道我要哪個軟體
要不然我也只能對著搜尋欄位發呆XD
而Android 我也不知道為什麼
總是可以下載到最新最好用的東西
軟體、遊戲什麼都不缺~~
真是窮人的好手機啊!!!!!!!!!!!讚!!!!
(不過我現在都用iPhone居多....)

當然還有很多安全性議題的文章,在此沒有列出
因為其實越獄後的iPhone只比root 過的 Android安全一點點(在此呼籲有越獄的朋友們,一定要把SSH關掉或改密碼!!!)
(但沒越獄的iPhone可能就比Android安全許多)
主要還是因為apk太容易被拆開再組合回去
這動作看似沒有意義,但最大的意義就在於拆開和組合中間的過程
拆開後可以修改內遷廣告的ID(讓收益變自己的)
也有可能加入隱藏的回傳資訊程式碼(原本就需要GPS和網路的App來說,裡面加進一小段回傳資訊的程式碼也是很難被發現的)
再包回apk,任意散播至各大論壇

說了這麼多
Android 真的無法再進步了嗎?
其實他還是在成長的XD
而且Linux kernel 擁有高移植性
所以對其他裝置來說,仍然有很大發展性(如:電視、智慧家庭....等等)

就手機而言目前除了Apple以外已經沒有其他選擇了
我以前也是個Apple hater,但實在受不了Android 只好跳槽當自己所討厭的人XDD
所以我仍然在期待年底的Windows Phone !!
原因? 下次再說吧....累了XDD


--------------
2012-04-27
再補一篇
Android平台上的盜版概況
http://www.inside.com.tw/2010/08/30/the-piracy-in-android

2012年4月8日

【DIY kernel】為context switch做準備, 實作Task



這部分程式已經提交到gitHub

故不將所有程式碼貼在網誌上瞜~~



task 共有四種狀態,分別是 ready, running, block(類似在休息, 記憶體不會被釋放), close

目前無法真正的將cpu使用權切換給其他task使用

只能修改各task的狀態

等下次將context switch實作之後才會有作用

這部分程式主要就是在這些狀態中切換

所以需要

list_t ready_list[MAX_PRIO];
list_t blocked_list;
list_t termination_list;

這三種list紀錄某種狀態下有哪些task

然後用

u32int task_table[MAX_TASK_NUM];

來放所有task, 有task設為1其餘為0 (所以這個os只能run MAX_TASK_NUM 個 task)

最後還有一個

u8int prioExistFlag[MAX_PRIO];

這是為了取出priority最高的 ready_list 所建的table (array)。

task 的結構如下


struct task{
node_t node;

void *sp;
void *entry;
void *parameter;
void *stack_addr;
u16int stack_size;

u8int priority;

u32int init_tick;
u32int remaining_tick;

u32int task_id;
TASK_STATE state;
char name[NAME_MAXLENTH];

timer_t *timer;
};

比較特別的是 void *sp (stack point)這指向 task 的 stack

void *entry 這指向這task要做的事情的function

void *stack_addr 就是指向stack的開頭摟

總共要實作的function有這些


task_t *task_create( const char *name,
void (*entry)(void *parameter),
void *parameter,
u16int stackSize,
u8int priority,
u16int tick);
s8int task_start( task_t *task );
s8int task_delete( task_t *task );
void task_yield();
s8int task_sleep( u32int tick );
s8int task_suspend( task_t *task );
s8int task_resume( task_t *task );
void task_remove( task_t *task );
void task_addReady( task_t *task );
task_t *ready_task( u8int priority );
u8int get_top_prio();
u32int get_task_id();

static void task_timeout(void *parameter);

在task_create裡


task_t *task_create( const char *name,
void (*entry)(void *parameter),
void *parameter,
u16int stackSize,
u8int priority,
u16int tick){

task_t *task;
u32int *stackAddr;
u32int task_id;

task_id = get_task_id();
if( task_id < 0 ){
return NULL;
}

task = (task_t *)kmalloc(sizeof(task_t));
if(task == NULL)
return NULL;

stackAddr = (void *)kmalloc(stackSize);
if( stackAddr == NULL ){
kfree(task);
return NULL;
}

for( int temp=0; temp<NAME_MAXLENTH; temp++ ){
task->name[temp] = name[temp];
}

task->task_id = task_id;
task->entry = (void *)entry;
task->parameter = parameter;
task->stack_addr = stackAddr;
task->stack_size = stackSize;
task->node.next = NULL;
task->node.prev = NULL;

task->init_tick = tick;
task->remaining_tick = tick;
task->priority = priority;
task->sp = (void *)( (void *)stackAddr + stackSize -4 );

memset( (u8int *)task->stack_addr, '?', task->stack_size );
task->sp = (void *)init_stack(task->sp,
 task->entry,
 task->parameter);
task_table[task->task_id] = 1;

task->timer = timer_create(task->name,
  task_timeout,
  task,
  0,
  SET_ONESHOT);

return task;
}

首先會取得task_id

就是從task_table裡取出value是0的key

之後就是初始化的動作

其中的init_stack在下次context switch時再一併講解

其餘工具的演算法或流程也不難

從一個狀態切換到下個狀態主要是

從原本的list裡移除(critical region)再加入另一個狀態的list中

詳細程式碼請至gitHub下載或線上參考~~

https://github.com/herb123456/DIY_Kernel

============================================

後來想想,還是直接在這寫下 init_stack 吧XD

init_stack在 stack.c 裡實作

是每個 task 專屬的一塊記憶體

裡面放的東西長這樣:


之後context switch 時 會將程式狀態存在這塊stack裡

詳細流程會在下一篇在講~~

2012年4月7日

【DIY kernel】實作 timer



timer 要做的事情也不難

了解整個過程之後code就比較好理解

首先 timer create 之後就將 timer 加入 timer_list

之後在每100個clock發生的interrupt內檢查timer_list

是否有timeout的timer和不是periodic mode(週期模式)的timer

發生timeout就執行 timeout handler

不是periodic mode 就設為inactive

然後還有額外的控制函數

timer_stop, timer_delete, timer_control(可控制timer mode)

接下來的code只會在比較特別的地方做講解!

先定義 timer 的結構和狀態


#define NAME_MAXLEN 20

struct timer{

node_t node;

char name[NAME_MAXLEN];
u8int flag;
void (*timeout_func)(void *parameter);
void *parameter;
u32int init_tick;
u32int timeout_tick;
};
typedef struct timer timer_t;

#define ACTIVATED 1<<0
#define PERIODIC 1<<1
typedef enum{
SET_TIME = 0,
GET_TIME,
SET_ONESHOT,
SET_PERIODIC
} TIMER_CMD_TYPE;


接下來就實作會用到的 function


void init_system_timer(){

init_list( &timer_list );

}



timer_t *timer_create( const char *name, void (*timeout)(void *parameter), void *parameter, u32int time, TIMER_CMD_TYPE flag ){

timer_t *timer = kmalloc( sizeof(timer_t) );
if( timer == NULL ){
kprintf("timer == NULL \n");
return NULL;
}else{
kprintf("timer != NULL \n");
}
timer_init(timer, name, timeout, parameter, time, flag);
return timer;
}

void timer_init( timer_t *timer, const char *name, void(*timeout)(void *parameter), void *parameter, u32int time, TIMER_CMD_TYPE flag ){
if( timer == NULL )
return;
switch(flag){
case SET_ONESHOT:
timer->flag &= ~PERIODIC;
break;
case SET_PERIODIC:
timer->flag |= PERIODIC;
break;
}
timer->flag &= ~ACTIVATED;
timer->timeout_func = timeout;
timer->parameter = parameter;
timer->timeout_tick = 0;
timer->init_tick = time;
}



timer_list 是個 list_t 型態的全域變數

list_t timer_list;


接著是實作 timer_start (將 timer 丟進 timer_list裡,並按照timeout大小排列)
和 timer_check (檢查timer_list是否有timeout的timer)


s8int timer_start( timer_t *timer ){

if( timer == NULL || timer->flag & ACTIVATED )

return ERROR;
timer_t *ptimer;
node_t *pnode, *last_node;
timer->timeout_tick = get_tick() + timer->init_tick;
disableInterrupt();
if( !is_Empty( &timer_list ) ){
pnode = first_node( &timer_list );
last_node = &timer_list.tail;
while( pnode != last_node || pnode == NULL ){
ptimer = (timer_t *)pnode;
if( ptimer->timeout_tick > timer->timeout_tick ){
append_list(pnode->prev, &timer->node);
break;
}else{
pnode = pnode->next;
}
}
if( pnode == last_node ){
insert_rear(&timer_list, &timer->node);
}
}else{
insert_rear(&timer_list, &timer->node);
}
enableInterrupt();
timer->flag |= ACTIVATED;
print_list(&timer_list);
return OK;
}

void timer_check(){
timer_t *ptimer;
node_t *pnode;
u32int current_tick = get_tick();
disableInterrupt();
if( !is_Empty(&timer_list) ){
pnode = first_node(&timer_list);
while( pnode != &timer_list.tail ){
ptimer = (timer_t *)pnode;
if( current_tick >= ptimer->timeout_tick ){
remove_node(&ptimer->node);
ptimer->timeout_func(ptimer->parameter);
if( (ptimer->flag & PERIODIC) && (ptimer->flag & ACTIVATED) ){
ptimer->flag &= ~ACTIVATED;
print_list(&timer_list);
timer_start(ptimer);
}else{
ptimer->flag &= ~ACTIVATED;
}
current_tick = get_tick();
pnode = pnode->next;
}else{
//kprintf("while break \n");
break;
}
}
}
enableInterrupt();
}


接下來是工具


s8int timer_stop( timer_t *timer ){

if( timer == NULL || !(timer->flag & ACTIVATED) )
return ERROR;
timer->flag &= ~ACTIVATED;
disableInterrupt();
remove_node(&timer->node);
enableInterrupt();
return OK;
}

s8int timer_delete( timer_t *timer ){
if( timer == NULL )
return ERROR;
disableInterrupt();
remove_node(&timer->node);
enableInterrupt();
kfree(timer);
return OK;
}

s8int timer_control( timer_t *timer, TIMER_CMD_TYPE cmd, u32int arg ){
if( timer == NULL )
return ERROR;
switch( cmd ){
case SET_TIME:
timer->init_tick = arg;
break;
case GET_TIME:
return timer->init_tick;
case SET_ONESHOT:
timer->flag &= ~PERIODIC;
break;
case SET_PERIODIC:
timer->flag |= PERIODIC;
break;
default:
return ERROR;
}
return OK;
}



我在gitHub上開了個 project
有興趣的人可以去看看