Bu sınır yalnızca fiziksel bellek için geçerlidir, yani tüm segmentler için ayrılan gerçek paylaşımlı bellek, çünkü shmat()
yalnızca ayrılmış segmenti işlem adres boşluğuna eşler. Bu çekirdek içinde iz olabilir
, bu sınır yeni segmentler (ns->shm_ctlall
karşılaştırma) ayırır newseg()
function içinde — işaretlendiğinde tek bir yer vardır. shmat()
implementation birçok şeyle meşgul, ama shmall limitine hiç dikkat etmiyor, böylece bir segmenti istediğiniz kadar çok haritalayabilirsiniz (iyi, adres alanı da sınırlıdır, ancak pratikte bu konuya nadiren bakıyorsunuz) limiti).
Ayrıca bu gibi basit bir programla userspace bazı testi deneyebilirsiniz
:
#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;
}
şu anda sistemde, daha sonra deneme tarafından kullanılan yukarıda ne shmall
sınırı sadece bir sayfasını ayarlar olduğu yapar nedir sayfa büyüklüğünde yeni bir segment almak ve (bütün başarıyla) iki kez eşleştirmek için, daha sonra bir sayfa daha boyutlu bir segment elde etmeye çalışır ve o (o /proc/sys/kernel/shmall
yazar çünkü süper kullanıcı olarak programı çalıştırmak) başaramazsa:
$ 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
Bu iyi bir açıklama. Birkaç söz var. Bu programın "/ proc/sys/kernel/shmall" yazabilmesi için sudo olarak çalıştırılması gerekiyor. Bir başka nokta ise programın çıkmasından sonra, "/ proc/sys/kernel/shmall" değerinin, bir sonraki yeniden başlatmaya kadar programda ayarlanan değerin beklediğini umuyorum. ama/proc/sys/kernel/shmall değerindeki bir kediyi yaptığımda, hala eski değeri 18446744073692774399 gösterir. Nedenini açıklar mısınız? – Nuetrino
@Nuetrino: çünkü orijinal shmall değerini geri yüklüyorum, sadece bir test, bu yüzden daha sonra sistem varsayılan değerine sahip olsanız iyi olur. –
Kodda tam olarak görmediğim kadarıyla geri yüklemediniz. – Nuetrino