semop() - Unix、Linux 系統呼叫
廣告
名稱semop、semtimedop - 訊號量操作語法
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
|
int semop(int semid, struct sembuf *sops, unsigned nsops);
int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout); 描述訊號量集中每個訊號量都具有以下關聯值
unsigned short semval; /* semaphore value */
unsigned short semzcnt; /* # waiting for zero */
unsigned short semncnt; /* # waiting for increase */
pid_t sempid; /* process that did last op */
|
semop() 對由 semid 指示的集合中選定的訊號量執行操作。由 sops 指向的陣列中的每個 nsops 元素都指定要對單個訊號量執行的操作。此結構的元素的型別為 struct sembuf,包含以下成員
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
|
sem_flg 中識別的標誌為 IPC_NOWAIT 和 SEM_UNDO。如果某個操作指定了 SEM_UNDO,則在程序終止時將自動撤消該操作。sops 中包含的操作集以原子方式執行,也就是說,這些操作同時執行,並且只有在所有操作都可以同時執行時才執行。如果並非所有操作都可以立即執行,則系統呼叫的行為取決於 sem_flg 的各個欄位中是否存在 IPC_NOWAIT 標誌,如下所示。 每個操作都對訊號量集的第 sem_num 個訊號量執行,其中訊號量的第一個編號為 0。有三種類型的操作,由 sem_op 的值區分。 如果 sem_op 是正整數,則此操作會將此值新增到訊號量值 (semval)。此外,如果為此操作指定了 SEM_UNDO,則系統會更新此訊號量的程序撤消計數 (semadj)。此操作始終可以繼續進行 - 它永遠不會強制程序等待。呼叫程序必須對訊號量集具有更改許可權。 如果 sem_op 為零,則程序必須對訊號量集具有讀取許可權。這是一個“等待為零”操作:如果 semval 為零,則操作可以立即繼續進行。否則,如果在 sem_flg 中指定了 IPC_NOWAIT,則 semop() 失敗,並設定 errno 為 EAGAIN(並且不執行 sops 中的任何操作)。否則,semzcnt(等待此訊號量值變為零的程序計數)加 1,並且程序休眠,直到發生以下情況之一
| 標籤 | 描述 |
| o |
semval 變為 0,此時 semzcnt 的值減 1。 |
| o | 訊號量集被移除:semop() 失敗,並設定 errno 為 EIDRM。 |
| o | 呼叫程序捕獲訊號:semzcnt 的值減 1,並且 semop() 失敗,並設定 errno 為 EINTR。 |
| o | semtimedop() 呼叫中指定的 timeout 時間限制到期:semop() 失敗,並設定 errno 為 EAGAIN。 |
| 如果 sem_op 小於零,則程序必須對訊號量集具有更改許可權。如果 semval 大於或等於 sem_op 的絕對值,則操作可以立即繼續進行:sem_op 的絕對值從 semval 中減去,並且,如果為此操作指定了 SEM_UNDO,則系統會更新此訊號量的程序撤消計數 (semadj)。如果 sem_op 的絕對值大於 semval,並且在 sem_flg 中指定了 IPC_NOWAIT,則 semop() 失敗,並設定 errno 為 EAGAIN(並且不執行 sops 中的任何操作)。否則,semncnt(等待此訊號量值增加的程序計數器)加 1,並且程序休眠,直到發生以下情況之一 |
| o |
semval 變為大於或等於 sem_op 的絕對值,此時 semncnt 的值減 1,sem_op 的絕對值從 semval 中減去,並且,如果為此操作指定了 SEM_UNDO,則系統會更新此訊號量的程序撤消計數 (semadj)。 |
| o | 訊號量集從系統中移除:semop() 失敗,並設定 errno 為 EIDRM。 |
| o | 呼叫程序捕獲訊號:semncnt 的值減 1,並且 semop() 失敗,並設定 errno 為 EINTR。 |
| o | semtimedop() 呼叫中指定的 timeout 時間限制到期:系統呼叫失敗,並設定 errno 為 EAGAIN。 |
成功完成後,由 sops 指向的陣列中指定的每個訊號量的 sempid 值將設定為呼叫程序的程序 ID。此外,sem_otime 將設定為當前時間。
semtimedop() 的行為與 semop() 完全相同,只是在呼叫程序將休眠的情況下,休眠的持續時間受 timeout 引數中傳遞的 timespec 結構指定的經過時間量的限制。如果指定的期限已到,則 semtimedop() 失敗,並設定 errno 為 EAGAIN(並且不執行 sops 中的任何操作)。如果 timeout 引數為 NULL,則 semtimedop() 的行為與 semop() 完全相同。 返回值如果成功,semop() 和 semtimedop() 返回 0;否則,它們返回 -1,並由 errno 指示錯誤。錯誤如果失敗,則 errno 將設定為以下值之一
| 標籤 | 描述 |
|
E2BIG | 引數 nsops 大於 SEMOPM,即每個系統呼叫允許的最大運算元。 |
|
EACCES | 呼叫程序沒有執行指定訊號量操作所需的許可權,並且沒有 CAP_IPC_OWNER 功能。 |
|
EAGAIN | 操作無法立即進行,並且在 sem_flg 中指定了 IPC_NOWAIT 或 timeout 中指定的時間限制已到期。 |
|
EFAULT | sops 或 timeout 引數中指定的地址不可訪問。 |
|
EFBIG | 對於某些操作,sem_num 的值小於 0 或大於或等於集合中訊號量的數量。 |
|
EIDRM | 訊號量集已移除。 |
|
EINTR | 在此係統呼叫中阻塞時,程序捕獲了訊號。 |
|
EINVAL | 訊號量集不存在,或者 semid 小於零,或者 nsops 的值為非正數。 |
|
ENOMEM | 某些操作的 sem_flg 指定了 SEM_UNDO,並且系統沒有足夠的記憶體來分配撤消結構。 |
|
ERANGE | 對於某些操作,sem_op+semval 大於 SEMVMX,即 semval 的實現相關的最大值。 |
註釋程序的 sem_undo 結構不會在 fork(2) 系統呼叫中繼承,但會在 execve(2) 系統呼叫中繼承。
semop() 在被訊號處理程式中斷後永遠不會自動重新啟動,無論在建立訊號處理程式時 SA_RESTART 標誌的設定如何。
semadj 是一個每程序整數,它只是指定了 SEM_UNDO 標誌的所有訊號量操作的(負)計數。當使用 semctl(2) 對 SETVAL 或 SETALL 請求直接設定訊號量的值時,所有程序中相應的 semadj 值都會被清除。 可以使用適當的 semctl(2) 呼叫檢索訊號量的 semval、sempid、semzcnt 和 semnct 值。 以下訊號量集資源限制會影響 semop() 呼叫
| 標籤 | 描述 |
|
SEMOPM | 一次 semop() 呼叫允許的最大運算元 (32)(在 Linux 上,此限制可以透過 /proc/sys/kernel/sem 的第三個欄位讀取和修改)。 |
|
SEMVMX | semval 允許的最大值:實現相關 (32767)。 |
實現對退出時調整最大值 (SEMAEM)、系統範圍內的最大撤消結構數 (SEMMNU) 和每個程序的最大撤消條目系統引數沒有內在限制。
semtimedop() 首次出現在 Linux 2.5.52 中,隨後被反向移植到核心 2.4.22 中。 錯誤當程序終止時,其關聯的 semadj 結構集用於撤消它使用 SEM_UNDO 標誌執行的所有訊號量操作的影響。這帶來了一個難題:如果這些訊號量調整中的一個(或多個)會導致嘗試將訊號量的值降低到零以下,則實現應該怎麼做?一種可能的方法是阻塞,直到所有訊號量調整都能夠執行。但這卻不可取,因為它可能會迫使程序終止阻塞任意長時間。另一種可能性是完全忽略此類訊號量調整(有點類似於在為訊號量操作指定 IPC_NOWAIT 時失敗)。Linux 採用了第三種方法:儘可能地降低訊號量值(即降到零)並允許程序終止立即繼續進行。在核心 2.6.x 中,x <= 10,存在一個錯誤,在某些情況下,它會阻止等待訊號量值變為零的程序在該值實際變為零時被喚醒。此錯誤在核心 2.6.11 中已修復。 符合標準SVr4、POSIX.1-2001。參見
廣告
|