सीमा केवल भौतिक स्मृति पर लागू होती है, जो सभी खंडों के लिए आवंटित वास्तविक साझा स्मृति है, क्योंकि shmat()
केवल नक्शा आवंटित सेगमेंट को प्रोसेस एड्रेस स्पेस में मैप करता है।
आप कर्नेल में यह पता लगा सकते हैं, वहाँ केवल एक ही जगह है जहाँ इस सीमा newseg()
function कि नए खंडों (ns->shm_ctlall
तुलना) आवंटित में — चेक किया गया है है। shmat()
implementation बहुत सारी चीजों से व्यस्त है, लेकिन शमल सीमा के बारे में बिल्कुल परवाह नहीं है, इसलिए आप एक सेगमेंट को जितनी बार चाहें मैप कर सकते हैं (ठीक है, पता स्थान भी सीमित है, लेकिन व्यवहार में आप शायद ही कभी इसकी परवाह करते हैं सीमा नहीं)।
तुम भी इस तरह एक साधारण प्रोग्राम के साथ यूज़रस्पेस से कुछ परीक्षण की कोशिश कर सकते हैं:
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
unsigned long int get_shmall() {
FILE *f = NULL;
char buf[512];
unsigned long int value = 0;
if ((f = fopen("/proc/sys/kernel/shmall", "r")) != NULL) {
if (fgets(buf, sizeof(buf), f) != NULL)
value = strtoul(buf, NULL, 10); // no proper checks
fclose(f); // no return value check
}
return value;
}
int set_shmall(unsigned long int value) {
FILE *f = NULL;
char buf[512];
int retval = 0;
if ((f = fopen("/proc/sys/kernel/shmall", "w")) != NULL) {
if (snprintf(buf, sizeof(buf), "%lu\n", value) >= sizeof(buf) ||
fwrite(buf, 1, strlen(buf), f) != strlen(buf))
retval = -1;
fclose(f); // fingers crossed
} else
retval = -1;
return retval;
}
int main()
{
int shm_id1 = -1, shm_id2 = -1;
unsigned long int shmall = 0, shmused, newshmall;
void *ptr1, *ptr2;
struct shm_info shminf;
if ((shmall = get_shmall()) == 0) {
printf("can't get shmall\n");
goto out;
}
printf("original shmall: %lu pages\n", shmall);
if (shmctl(0, SHM_INFO, (struct shmid_ds *)&shminf) < 0) {
printf("can't get SHM_INFO\n");
goto out;
}
shmused = shminf.shm_tot * getpagesize();
printf("shmused: %lu pages (%lu bytes)\n", shminf.shm_tot, shmused);
newshmall = shminf.shm_tot + 1;
if (set_shmall(newshmall) != 0) {
printf("can't set shmall\n");
goto out;
}
if (get_shmall() != newshmall) {
printf("something went wrong with shmall setting\n");
goto out;
}
printf("new shmall: %lu pages (%lu bytes)\n", newshmall, newshmall * getpagesize());
printf("shmget() for %u bytes: ", (unsigned int) getpagesize());
shm_id1 = shmget(IPC_PRIVATE, (size_t)getpagesize(), IPC_CREAT | 0666);
if (shm_id1 < 0) {
printf("failed: %s\n", strerror(errno));
goto out;
}
printf("ok\nshmat 1: ");
ptr1 = shmat(shm_id1, NULL, 0);
if (ptr1 == 0) {
printf("failed\n");
goto out;
}
printf("ok\nshmat 2: ");
ptr2 = shmat(shm_id1, NULL, 0);
if (ptr2 == 0) {
printf("failed\n");
goto out;
}
printf("ok\n");
if (ptr1 == ptr2) {
printf("ptr1 and ptr2 are the same with shm_id1\n");
goto out;
}
printf("shmget() for %u bytes: ", (unsigned int) getpagesize());
shm_id2 = shmget(IPC_PRIVATE, (size_t)getpagesize(), IPC_CREAT | 0666);
if (shm_id2 < 0)
printf("failed: %s\n", strerror(errno));
else
printf("ok, although it's wrong\n");
out:
if (shmall != 0 && set_shmall(shmall) != 0)
printf("failed to restrore shmall\n");
if (shm_id1 >= 0 && shmctl(shm_id1, IPC_RMID, NULL) < 0)
printf("failed to remove shm_id1\n");
if (shm_id2 >= 0 && shmctl(shm_id2, IPC_RMID, NULL) < 0)
printf("failed to remove shm_id2\n");
return 0;
}
क्या करता है यह shmall
सीमा सिर्फ एक जो वर्तमान प्रणाली है, तो कोशिश करता द्वारा किया जाता है इसके बाद के संस्करण पेज सेट है पेज आकार नया खंड मिलता है और इसे दो बार के नक्शे (सभी सफलतापूर्वक) करने के लिए है, तो एक और पृष्ठ आकार खंड निकलने की कोशिश करता है और ऐसा करने के लिए है कि (कार्यक्रम क्रियान्वित सुपर उपयोगकर्ता के रूप में, क्योंकि यह /proc/sys/kernel/shmall
को लिखते हैं) में विफल रहता है:
$ sudo ./a.out
original shmall: 18446744073708503040 pages
shmused: 21053 pages (86233088 bytes)
new shmall: 21054 pages (86237184 bytes)
shmget() for 4096 bytes: ok
shmat 1: ok
shmat 2: ok
shmget() for 4096 bytes: failed: No space left on device
यह एक अच्छी व्याख्या है। मेरे पास कुछ टिप्पणियां हैं। "/ Proc/sys/kernel/shmall" को लिखने में सक्षम होने के लिए इस कार्यक्रम को सुडो के रूप में चलाने की आवश्यकता है। एक और टिप्पणी कार्यक्रम के निष्कर्ष के बाद है, मुझे उम्मीद है कि "/ proc/sys/kernel/shmall" का मान अगले रीबूट तक प्रोग्राम में मान सेट रहता है। लेकिन जब मैं/proc/sys/kernel/shmall पर मान की बिल्ली करता हूं, तो यह अभी भी पुराना मान 18446744073692774399 दिखाता है। क्या आप समझा सकते हैं? – Nuetrino
@ न्यूट्रिनो: ऐसा इसलिए है क्योंकि मैं मूल शमल मूल्य को पुनर्स्थापित कर रहा हूं, यह सिर्फ एक परीक्षण है, इसलिए मुझे लगता है कि इसके बाद आपके पास उचित सिस्टम-डिफ़ॉल्ट मान बेहतर होगा। –
कोड में बिल्कुल नहीं, जहां तक मैं देख सकता हूं कि आप इसे पुनर्स्थापित नहीं करते हैं। – Nuetrino