壓縮:
tar Jcvf
隨手寫寫的筆記... 排版一直衝突 ...(´・ω・`)
壓縮:
tar Jcvf
年代久遠的東西
好久沒做都快忘光了
以前學校學的東西都忘的差不多了
這麼多年來專案做了不少個
但也只有在每次專案剛開始的時候才會用到這些東西
時間一久就什麼都忘光了= ="
這篇是在記錄
在 Linux 中 POSIX shared memory 跟 dynamic shared library 合併使用的方式
其實這個不重要
重要的是你的 Linux 系統本體所放的 glibc
不要因為閹割太多而導致 ld.so 的功能有缺失或是整個不見
基本上這樣的 code 在 x86 或是 arm 都沒有問題
如果 ld.so 不存在的話基本上這篇不適合可以直接左轉上一頁!!
這次預期的目標是
在一個 shared library 中製作一個 shared memory
然後讓另外兩個獨立的執行檔可以共同存取它
在 Linux 中 IPC 其實有不少可以用
這次選用 POSIX 的方式也沒有什麼特別的原因
單純就是懶惰...(;‘∀’)
這次總共 5 個檔案
foo.c / foo.h 用來製作 shared library 本人
test_dll.c 用來製作第一個執行檔
test_dll_2.c 用來製作第二個執行檔
makefile 用來編譯
foo.h
這個檔案裡的東西實際上只是給人看的而已
這樣跟其他人在 co-work 的時候至少別人有東西可以參考
不過編譯跟執行實際上是不需要的
foo.c
因為這次的功能設計上來說
只會在開機的時候執行第一次之後就再也不會釋放
所以就偷懶直接把 init
放到了 constructor
裡面
然後把 deinit
放到了 destructor
裡面
實際上如果沒有特別的需求的話
下面這兩行並不需要
直接放到正常的流程裡面執行就好
static void __attribute__ ((constructor)) init_lib(void);
static void __attribute__ ((destructor)) deinit_lib(void);
上面這兩行的目的在於
當這個檔案被執行到的時候會先直接執行 constructor
的部分把 init()
做完
當這個檔案被生命週期到盡頭的時候會執行 destructor
的部分做 deinit()
不過 constructor / destructor 的部分不在這篇的範圍裡面所以跳過(;^ω^)
另外因為這次的 sample code 沒有什麼功能
所以實際上 foo.h 沒有也沒差
不過為了以後功能越加越多
所以還是先把它保留下來了
這個檔案是這篇的主角之一
Shared memory 實際上就是由他建立
然後讓其他執行檔案可以使用
主要是下面這三行
// create shared memory
int fd = shm_open("/posix_shared_memory", O_CREAT | O_RDWR | O_EXCL, 0600);
// resize
ftruncate(fd, ALLOCATE_SHARED_MEMORY_SIZE);
// mount
shared_memory_address = mmap(NULL, ALLOCATE_SHARED_MEMORY_SIZE, PORT_READ | PORT_WRITE, MAP_SHARED, fd, 0);
圖中的 if (fd >= 0)
是因為當兩個執行檔呼叫的時候為了避免重複產生而做的基本檢查
fflush()
跟msync()
這純粹只是我們的系統會一直卡 buffer
所以硬是給他加上去的而已 = ="
然後只要是遇到非同步讀寫都會遇到搶資源的問題
所以還是需要做點保護
至少保證 write after read 或 read after write
所以在 init()
的最後弄了一個 semaphore 用來卡存取狀態
這個鎖之後會給另外兩個獨立的執行檔使用
同樣偷懶的直接用 POSIX 的 semaphore
sem_t " semaphore_mutex = NULL;
semaphore_mutex = sem_open("/posix_semaphore", O_RDWR | O_CREAT, 0600, 1);
另外有個奇妙的地方
就是shm_open()
跟sem_open()
根據 man 所提供的說明
name 應該都要是 “/” 開頭的字串
不過實際上試了一下就算不加 “/”
他還是會掛到相對應的位置
理論上應該都可以在 /dev/shm
底下找到他們
在deinit()
中放入munmap()
實際上 munmap()
應該在存取完之後就直接放掉
不過這邊為了測試所以把它留到了 deinit()
的時候才執行
test_dll.c
#include <dlfcn.h>/* for dl* function */
這個檔案用到的
dlopen()
、dlsym()
、dlclose()
都是這裡面的東西
然後 load library
// libfoo.so 是用前面的 foo.c 產生出來的
// 理論上它在哪邊都沒有問題
// 只要找的到他本人就可以
void * handle = dlopen("./libfoo.so", RTLD_LAZY);
這和一般的 shared library 不同
一般的 shared library 在程式開始的時候就會去檢查 shared library 在不在了
而使用 dlopen()
載入 function 的方式
會讓 libfoo.so 只有在執行到這行的時候才會被載入
在存取 shared memory 之前
先卡一個 semaphore
// 開一個 semaphore 用來卡讀寫狀態
sem_t * sem_mutex = sem_open("/posix_semaphore", O_RDWR | O_CREAT, 0600, 1);
// 等待進入 critical section
sem_wait(sem_mutex);
個人習慣在 mmap()
之前就先上鎖了
雖然這樣會讓 critical section 變得很長
但是為了確保 mmap()
在動作時不會在中途有資料沒有被更新
導致資料不同步的問題
所以個人習慣會把鎖加在 mmap()
之前
實際上 cached/uncached 的同步還有很多東西要做
不過那不是這篇的重點所以也是先跳過(;^ω^)
然後 shm_open()
→ftruncate()
→mmap()
這裡的步驟跟前面的 foo.c 是一樣的就先略過了
接下來就是對 mmap()
返回的位置做存取了
操作完這塊空間之後就可以用 munmap()
把這塊空間放掉了
通常卡到 cached/uncached 的時候
都會在 munmap()
之前多做 invalidate 跟 flush 的動作
這樣才有辦法保證資料有確實寫入 uncached 的空間中
釋放完空間之後
就要趕快把 semaphore 給打開
不然鎖卡太久可能會造成其他問題
// 解鎖離開 critical section
sem_post(sem_mutex);
最後 shared library 確認用完之後
就可以把它給卸載了
// 釋放 shared library
dlclose(handle);
這裡沒有用到 sem_unlink()
是因為我們的系統預設沒有需要用到這裡的地方
所以就直接忽略掉沒使用了…OTL
test_dll_2.c
這個檔案跟 test_dll.c 大部分是一樣的
這個只是用來當作第二個獨立執行檔用的而已
makefile
編譯 libfoo.so
的時候要 -fPIC
不然程式載入不同系統時位置會出問題
然後加 -shared
給 LD
編譯執行檔的時候要加 -lrt -lpthread
這樣才能用 shared library
然後加 -ldl
這樣 dl* function
才能有作用
./test &
./test2
執行完之後可以在 /dev/shm
底下
找到 posix_shared_memory
跟 sem.posix_semaphore
原因是因為程式執行完
沒有執行 shm_unlink()
跟 sem_unlink()
所以最後這兩個物件都沒有被消除
不過這兩個物件在重開機之後就會不見了
所以以我們的系統來說其實用不太到
我們 target 的系統竟然沒有 /dev/shm
這個路徑
所以一開始的時候一直出現 bus error
不過後來手動建立這個路徑之後就沒問題了
身為一個 Android BSP 工程師
不只是底層的 system bring up
或是 Linux kernel driver
又或是 HAL,NDK 串接
連上層 application 都要會呢 (´・ω・`)
真的變成名符其實的 Android 全端工程師了=v=
在 Android Studio 中使用 OpenCV for Android
這篇大概已經拖了2、3年了
一直都沒時間寫
然後每次要用就一直重蹈覆轍到處找資料= =
趁現在有時間趕快來寫一下
沒有...
到 OpenCV 官網直接把 Android 版本的壓縮檔給抓下來
https://opencv.org/releases/
把壓縮檔裡面的這個資料夾解壓縮出來
因為這個資料夾的東西匯入專案之後就不重要了
所以隨便找個地方放就可以了
如果有舊的專案
這個步驟就直接略過就好
這邊選什麼 template 都可以
因為這個不會對接下來的動作造成影響
找個地方存放專案
然後語言看自己喜好就好
這邊用 kotlin 當示範
選好之後按 [Finish]
然後就會看到它自己開始安裝一些 components
完成之後就會看到專案了
這個時候有件很重要的事
等待它!!
因為這時候 Gradle 會開始下載一些套件跟同步整個專案
所以這個時候不等它的話
等等會出現一堆莫名其妙的錯誤!!
根據每台電腦跟網路的差異性
大約需要 1 ~ 30 分鐘不等的時間
同步完之後
就可以看到 log 裡出現跟下面這張圖差不多的東西了
[File]→[New]→[Import Module…]
然後就會跳出下面這個匯入用的框框
這邊有件事情很重要
剛剛解壓縮出來的路徑應該是
path/to/OpenCV-android-sdk
但是這邊要指定的 [Source directory]
是它的下一層的 [SDK] 資料夾
不然他會找不到東西的說= =
選完之後就 [Finish]
然後跟舊版的有些差異是
舊版的會需要輸入 [Module Name]
但是新的這個版本沒有地方輸入這個東西
所以等等就會產生一個很微妙的狀況
因為 Module Name 被自動設定成了
被指定的那個資料夾的名稱
所以等等這個 module 的名稱就變成了前面寫的 [SDK]
然後自動 sync 的時候就出現錯誤了Σ( ̄□ ̄|||)
這時候只要按下 error log 中
那行藍色提示安裝 NDK
就會自動跳出跟下面這張圖一樣的安裝畫面了
安裝完成之後按下那顆藍色的 [Finish] 按鈕
它就會自動開始同步專案了
然後根據電腦的效能會需要等個大概幾分鐘不等的時間
最後要在 log 中看到
CONFIGURE SUCCESSFUL 才算成功!!
然後在左上的 Project View 中
找到 [Android] 的字樣
通常專案的顯示預設是用 Android Project 來排列
不過這樣是看不到剛剛匯入的東西的!!
所以這時候要把 Project View 切換成 [Project]
切換完之後
就可以在下面的的 Project View 中
找到剛剛匯入的 [SDK] 資料夾了!!
這個東西就是剛剛匯入的 OpenCV 了!!
然後抱怨一下
以前舊版的還可以設定 module name 的時候
至少可以讓這個顯示的名字好看一點
現在這樣真的很難懂 = =
找到左上角的 [File]→[Project Structures…]
然後會跳出專案的設定
最左邊的 column 切換到 [Dependencies]
旁邊的 Modules 切換到 [app]
這邊的 [app] 是你的主要專案
所以有可能會不一樣
然後跟下圖一樣
按一下旁邊的 [+]
選到 [3 Module Dependency]
這時候就會看到跟下圖一樣的相依性追加畫面了
圖中的 [sdk] 就是剛剛匯入的 OpenCV
只是因為前面沒有設定名字
所以這邊根本看不出來他是什麼= =
然後把 [sdk] 打勾按 [OK]
這時候會回到剛剛的畫面
在畫面中的 [Dependency] 就會多了剛剛的 [sdk] 資料夾了
這時候按一下右下角的 [Apply]
然後就會看到跟下圖一樣的浮水印出現了
這時候 Gradle 會開始同步專案
沒意外的話同步完之後按藍色的 [OK] 離開
這時候會在 log 中看到 [CONFIGURE SUCCESSFUL]
到這邊基本上就設定完了!!
這個步驟有點神奇
並不是一定要做
如果之後在 build 的時候都沒有出現問題的話
基本上這步可以不用做
不過之後 build 有出問題的話
可以考慮一下這個步驟
先把 Project View 切換回 [Android]
然後找到 Gradle Scripts
底下有個 build.gradle (Module: app)
然後把它打開來
找到 [compileSdkVersion] 這個數值
然後記得它
接著再打開 build.gradle (Module: sdk)
然後把這個的 compileSdkVersion 改成剛剛那個數字
這樣至少可以減少版本不同步的問題
然後在 code 裡面加入測試用的 code
if (!OpenCVLoader.initDebug()) {
Log.i("OpenCV", "Failed");
} else {
Log.i("OpenCV", "Succeeded");
}
直接 build …
沒意外的話
就會看到 [BUILD SUCCESSFUL] 了
這篇就這樣了
就像這篇的標題一樣
這篇主要是用來記錄怎麼架設 GitLab
GitLab 主要有 2 個版本
一個是 CE
一個是 EE
CE 是 Community Edition
EE 是 Enterprise Edition
因為 CE 不用錢
所以這篇裝的是 CE 版
sudo apt update
sudo apt upgrade -y
sudo apt install curl openssh-server ca-certificates postfix -y
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
sudo apt install gitlab-ce -y
安裝完之後開啟 /etc/gitlab/gitlab.rb 這個檔案
sudo gedit /etc/gitlab/gitlab.rb
找到 external_url 這行
然後把 URL 寫進去
看起來會像下面這樣
external_url 'http://any.address'
然後讓 gitlab 做一次重新設定
sudo gitlab-ctl reconfigure
最後設定防火牆
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
下面這行可以確認防火牆服務的狀態
sudo ufw status
就這樣沒了!!
根據官方文件描述
1 core supports up to 100 users but the application can be a bit slower due to having all workers and background jobs running on the same core
2 cores is recommended minimum number of cores and supports up to 100 users
4 cores supports up to 500 users
8 cores supports up to 1,000 users
32 cores supports up to 5,000 users
基本上如果有大於 5,000 使用者的需求
就需要做其他的設定來換取系統的效能
不過因為我用不到這麼多人的需求
所以就不考慮了
是說現在這個時間點也找不到一台 1 核心的電腦就是了
當然如果是用 VM 架的那就另當別論了...
4GB RAM + 4GB swap supports up to 100 users but it will be very slow
8GB RAM is the recommended minimum memory size for all installations and supports up to 100 users
16GB RAM supports up to 500 users
32GB RAM supports up to 1,000 users
128GB RAM supports up to 5,000 users
官方文件上是建議最少 8GB 啦
雖然它說 4GB 也可以
但是另外 4GB 是靠 swap 來運作的話基本上就慢了呀 @@
而且根據 repo 的大小有可能會需要更多或更少的記憶體
這就要看使用情況而定了
官方建議至少 5 ~ 10 GB
看需求而定
目前 12.1 以上的版本是支援 PostgreSQL
之前的 MySQL/MariaDB 建議是在升級之前移動到 PostgreSQL 去
Firefox
Chrome/Chromium
Safari
Microsoft Edge
Internet Explorer 11
※不支援 JavaScript disabled 的環境
反正在 ubuntu 上不管做什麼
只要用到 package 相依的東西就會要做這個動作
不過其實也不是這麼必要就是了
就自己選擇看要不要做就好...
sudo apt update
sudo apt upgrade -y
sudo apt install curl openssh-server ca-certificates postfix -y
先追加 GitLab package repository
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
追加完之後先暫停一下
在執行安裝之前
要講一個東西叫做 EXTERNAL_URL
這個東西就是之後要被外部存取的 URL
依照官方文件的描述
要先指定這個變數再進行安裝
所以看起來會像下面這樣
sudo EXTERNAL_URL="https://gitlab.example.com" apt install gitlab-ce
但是如果這個時候還沒有要決定 url 的話也沒關係
就直接向下面這樣給他安裝也不會有問題
sudo apt install gitlab-ce -y
為什麼要把這個拿出來講的的原因是因為
我一開始沒有看文件就隨邊敲了個安裝指令
然後他就跳警告訊息了 =口=
不過這個值可以從檔案直接改所以也沒什麼影響就是了w
這個檔案是 /etc/gitlab/gitlab.rb
找個 editor 把這個檔案打開
sudo gedit /etc/gitlab/gitlab.rb
然後在裡面可以找到一行
external_url
然後空空的東西
這邊就是可以填入 url 的地方
填完看起來會像下面這樣
external_url 'http://192.168.8.106'
這邊因為沒有要上 global 的需求
所以只給個 local ip 就可以了
然後就是跑一次 GitLab 的重新設定
sudo gitlab-ctl reconfigure
這個沒設的話可能會沒辦法存取喔...
這裡用 ufw 來設定
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
然後啟動它
sudo ufw allow enable
檢查它的狀態
sudo ufw status
是說因為 GitLab 本身已經內建 Nginx 了
所以原本如果有執行其他 httpd 的話可能會衝突
它的預設 port 是 80
如果已經有其他 web 也佔用了的話
這樣就要另外設定了!!
sudo gitlab-ctl stop
sudo gitlab-ctl start
在一般普通的 Ubuntu 底下
通常可以使用 systemd 來做 server management
但是 WSL 的 Ubuntu 有自己的 init system
所以基本上 systemctl 指令是沒有辦法使用的
在敲下面這個 SSH 啟動的指令的時候就遇到了問題
sudo systemctl start sshd
sudo service ssh restart
Could not load host key: /etc/ssh/ssh_host_rsa_key
Could not load host key: /etc/ssh/ssh_host_ecdsa_key
Could not load host key: /etc/ssh/ssh_host_ed25519_key
* Restarting OpenBSD Secure Shell server sshd
Could not load host key: /etc/ssh/ssh_host_rsa_key
Could not load host key: /etc/ssh/ssh_host_ecdsa_key
Could not load host key: /etc/ssh/ssh_host_ed25519_key
這時候只要敲一個指令就行了
sudo ssh-keygen -A
然後看到下面這個訊息就行了
ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519
然後在重啟 ssh service
sudo service ssh restart
這時候會看到下面這行訊息就表示成功了
* Restarting OpenBSD Secure Shell server sshd [ OK ]
void yuyv_to_rgb(unsigned char* yuv,unsigned char* rgb, int image_width, int image_height)
{
unsigned int i;
unsigned char* y0 = yuv + 0;
unsigned char* u0 = yuv + 1;
unsigned char* y1 = yuv + 2;
unsigned char* v0 = yuv + 3;
unsigned char* r0 = rgb + 0;
unsigned char* g0 = rgb + 1;
unsigned char* b0 = rgb + 2;
unsigned char* r1 = rgb + 3;
unsigned char* g1 = rgb + 4;
unsigned char* b1 = rgb + 5;
float rt0 = 0, gt0 = 0, bt0 = 0, rt1 = 0, gt1 = 0, bt1 = 0;
for(i = 0; i <= (image_width * image_height) / 2 ;i++)
{
bt0 = 1.164 * (*y0 - 16) + 2.018 * (*u0 - 128);
gt0 = 1.164 * (*y0 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
rt0 = 1.164 * (*y0 - 16) + 1.596 * (*v0 - 128);
bt1 = 1.164 * (*y1 - 16) + 2.018 * (*u0 - 128);
gt1 = 1.164 * (*y1 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
rt1 = 1.164 * (*y1 - 16) + 1.596 * (*v0 - 128);
if(rt0 > 250) rt0 = 255;
if(rt0 < 0) rt0 = 0;
if(gt0 > 250) gt0 = 255;
if(gt0 < 0) gt0 = 0;
if(bt0 > 250) bt0 = 255;
if(bt0 < 0) bt0 = 0;
if(rt1 > 250) rt1 = 255;
if(rt1 < 0) rt1 = 0;
if(gt1 > 250) gt1 = 255;
if(gt1 < 0) gt1 = 0;
if(bt1 > 250) bt1 = 255;
if(bt1 < 0) bt1 = 0;
*r0 = (unsigned char)rt0;
*g0 = (unsigned char)gt0;
*b0 = (unsigned char)bt0;
*r1 = (unsigned char)rt1;
*g1 = (unsigned char)gt1;
*b1 = (unsigned char)bt1;
yuv = yuv + 4;
rgb = rgb + 6;
if(yuv == NULL)
break;
y0 = yuv;
u0 = yuv + 1;
y1 = yuv + 2;
v0 = yuv + 3;
r0 = rgb + 0;
g0 = rgb + 1;
b0 = rgb + 2;
r1 = rgb + 3;
g1 = rgb + 4;
b1 = rgb + 5;
}
}
int image_width = 1920;
int image_height = 1080;
unsigned char * p_yuyv_data = (unsigned char *)malloc(sizeof(unsigned char) * image_width * image_height * 2);
unsigned char * p_rgb_data = (unsigned char *)malloc(sizeof(unsigned char) * image_width * image_height * 3);
// yuyv の処理
// ... 省略
yuyv_to_rgb(p_yuyv_data, p_rgb_data);
// rgb の処理
// ... 省略
free(p_yuyv_data);
free(p_rgb_data);
$ export LC_ALL=C
flex-2.5.39: loadlocale.c:130: _nl_intern_locale_data: Assertion `cnt < (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' failed.
Aborted (core dumped)
ninja: build stopped: subcommand failed.
ninja failed with: exit status 1
$ export LC_ALL=C
locale 這個東西是用來設定執行的程式的不同語言環境用的