Mercurial > emacs
comparison src/ralloc.c @ 31606:f0f7e75e83c4
Remove everything having to do with the use of mmap.
| author | Gerd Moellmann <gerd@gnu.org> |
|---|---|
| date | Thu, 14 Sep 2000 15:14:28 +0000 |
| parents | 5b50ac5d207d |
| children | d8d68cbd1113 |
comparison
equal
deleted
inserted
replaced
| 31605:c3073b2c8dfa | 31606:f0f7e75e83c4 |
|---|---|
| 924 relinquish (); | 924 relinquish (); |
| 925 | 925 |
| 926 return address; | 926 return address; |
| 927 } | 927 } |
| 928 | 928 |
| 929 #ifndef REL_ALLOC_MMAP | |
| 930 | 929 |
| 931 /* Allocate a relocatable bloc of storage of size SIZE. A pointer to | 930 /* Allocate a relocatable bloc of storage of size SIZE. A pointer to |
| 932 the data is returned in *PTR. PTR is thus the address of some variable | 931 the data is returned in *PTR. PTR is thus the address of some variable |
| 933 which will use the data area. | 932 which will use the data area. |
| 934 | 933 |
| 1215 assert (first_heap->bloc_start == break_value); | 1214 assert (first_heap->bloc_start == break_value); |
| 1216 } | 1215 } |
| 1217 | 1216 |
| 1218 #endif /* DEBUG */ | 1217 #endif /* DEBUG */ |
| 1219 | 1218 |
| 1220 #endif /* not REL_ALLOC_MMAP */ | |
| 1221 | |
| 1222 | |
| 1223 /*********************************************************************** | |
| 1224 Implementation based on mmap | |
| 1225 ***********************************************************************/ | |
| 1226 | |
| 1227 #ifdef REL_ALLOC_MMAP | |
| 1228 | |
| 1229 #include <sys/types.h> | |
| 1230 #include <sys/mman.h> | |
| 1231 | |
| 1232 #ifndef MAP_ANON | |
| 1233 #ifdef MAP_ANONYMOUS | |
| 1234 #define MAP_ANON MAP_ANONYMOUS | |
| 1235 #else | |
| 1236 #define MAP_ANON 0 | |
| 1237 #endif | |
| 1238 #endif | |
| 1239 | |
| 1240 #include <stdio.h> | |
| 1241 #include <errno.h> | |
| 1242 | |
| 1243 #if MAP_ANON == 0 | |
| 1244 #include <fcntl.h> | |
| 1245 #endif | |
| 1246 | |
| 1247 | |
| 1248 /* Memory is allocated in regions which are mapped using mmap(2). | |
| 1249 The current implementation lets the system select mapped | |
| 1250 addresses; we're not using MAP_FIXED in general, except when | |
| 1251 trying to enlarge regions. | |
| 1252 | |
| 1253 Each mapped region starts with a mmap_region structure, the user | |
| 1254 area starts after that structure, aligned to MEM_ALIGN. | |
| 1255 | |
| 1256 +-----------------------+ | |
| 1257 | struct mmap_info + | | |
| 1258 | padding | | |
| 1259 +-----------------------+ | |
| 1260 | user data | | |
| 1261 | | | |
| 1262 | | | |
| 1263 +-----------------------+ */ | |
| 1264 | |
| 1265 struct mmap_region | |
| 1266 { | |
| 1267 /* User-specified size. */ | |
| 1268 size_t nbytes_specified; | |
| 1269 | |
| 1270 /* Number of bytes mapped */ | |
| 1271 size_t nbytes_mapped; | |
| 1272 | |
| 1273 /* Pointer to the location holding the address of the memory | |
| 1274 allocated with the mmap'd block. The variable actually points | |
| 1275 after this structure. */ | |
| 1276 POINTER_TYPE **var; | |
| 1277 | |
| 1278 /* Next and previous in list of all mmap'd regions. */ | |
| 1279 struct mmap_region *next, *prev; | |
| 1280 }; | |
| 1281 | |
| 1282 /* Doubly-linked list of mmap'd regions. */ | |
| 1283 | |
| 1284 static struct mmap_region *mmap_regions; | |
| 1285 | |
| 1286 /* File descriptor for mmap. If we don't have anonymous mapping, | |
| 1287 /dev/zero will be opened on it. */ | |
| 1288 | |
| 1289 static int mmap_fd; | |
| 1290 | |
| 1291 /* Temporary storage for mmap_set_vars, see there. */ | |
| 1292 | |
| 1293 static struct mmap_region *mmap_regions_1; | |
| 1294 static int mmap_fd_1; | |
| 1295 | |
| 1296 /* Value is X rounded up to the next multiple of N. */ | |
| 1297 | |
| 1298 #define ROUND(X, N) (((X) + (N) - 1) / (N) * (N)) | |
| 1299 | |
| 1300 /* Size of mmap_region structure plus padding. */ | |
| 1301 | |
| 1302 #define MMAP_REGION_STRUCT_SIZE \ | |
| 1303 ROUND (sizeof (struct mmap_region), MEM_ALIGN) | |
| 1304 | |
| 1305 /* Given a pointer P to the start of the user-visible part of a mapped | |
| 1306 region, return a pointer to the start of the region. */ | |
| 1307 | |
| 1308 #define MMAP_REGION(P) \ | |
| 1309 ((struct mmap_region *) ((char *) (P) - MMAP_REGION_STRUCT_SIZE)) | |
| 1310 | |
| 1311 /* Given a pointer P to the start of a mapped region, return a pointer | |
| 1312 to the start of the user-visible part of the region. */ | |
| 1313 | |
| 1314 #define MMAP_USER_AREA(P) \ | |
| 1315 ((POINTER_TYPE *) ((char *) (P) + MMAP_REGION_STRUCT_SIZE)) | |
| 1316 | |
| 1317 /* Function prototypes. */ | |
| 1318 | |
| 1319 static int mmap_free P_ ((struct mmap_region *)); | |
| 1320 static int mmap_enlarge P_ ((struct mmap_region *, int)); | |
| 1321 static struct mmap_region *mmap_find P_ ((POINTER_TYPE *, POINTER_TYPE *)); | |
| 1322 POINTER_TYPE *r_alloc P_ ((POINTER_TYPE **, size_t)); | |
| 1323 POINTER_TYPE *r_re_alloc P_ ((POINTER_TYPE **, size_t)); | |
| 1324 void r_alloc_free P_ ((POINTER_TYPE **ptr)); | |
| 1325 | |
| 1326 | |
| 1327 /* Return a region overlapping address range START...END, or null if | |
| 1328 none. END is not including, i.e. the last byte in the range | |
| 1329 is at END - 1. */ | |
| 1330 | |
| 1331 static struct mmap_region * | |
| 1332 mmap_find (start, end) | |
| 1333 POINTER_TYPE *start, *end; | |
| 1334 { | |
| 1335 struct mmap_region *r; | |
| 1336 char *s = (char *) start, *e = (char *) end; | |
| 1337 | |
| 1338 for (r = mmap_regions; r; r = r->next) | |
| 1339 { | |
| 1340 char *rstart = (char *) r; | |
| 1341 char *rend = rstart + r->nbytes_mapped; | |
| 1342 | |
| 1343 if (/* First byte of range, i.e. START, in this region? */ | |
| 1344 (s >= rstart && s < rend) | |
| 1345 /* Last byte of range, i.e. END - 1, in this region? */ | |
| 1346 || (e > rstart && e <= rend) | |
| 1347 /* First byte of this region in the range? */ | |
| 1348 || (rstart >= s && rstart < e) | |
| 1349 /* Last byte of this region in the range? */ | |
| 1350 || (rend > s && rend <= e)) | |
| 1351 break; | |
| 1352 } | |
| 1353 | |
| 1354 return r; | |
| 1355 } | |
| 1356 | |
| 1357 | |
| 1358 /* Unmap a region. P is a pointer to the start of the user-araa of | |
| 1359 the region. Value is non-zero if successful. */ | |
| 1360 | |
| 1361 static int | |
| 1362 mmap_free (r) | |
| 1363 struct mmap_region *r; | |
| 1364 { | |
| 1365 if (r->next) | |
| 1366 r->next->prev = r->prev; | |
| 1367 if (r->prev) | |
| 1368 r->prev->next = r->next; | |
| 1369 else | |
| 1370 mmap_regions = r->next; | |
| 1371 | |
| 1372 if (munmap (r, r->nbytes_mapped) == -1) | |
| 1373 { | |
| 1374 fprintf (stderr, "munmap: %s\n", emacs_strerror (errno)); | |
| 1375 return 0; | |
| 1376 } | |
| 1377 | |
| 1378 return 1; | |
| 1379 } | |
| 1380 | |
| 1381 | |
| 1382 /* Enlarge region R by NPAGES pages. NPAGES < 0 means shrink R. | |
| 1383 Value is non-zero if successful. */ | |
| 1384 | |
| 1385 static int | |
| 1386 mmap_enlarge (r, npages) | |
| 1387 struct mmap_region *r; | |
| 1388 int npages; | |
| 1389 { | |
| 1390 char *region_end = (char *) r + r->nbytes_mapped; | |
| 1391 size_t nbytes; | |
| 1392 int success = 0; | |
| 1393 | |
| 1394 if (npages < 0) | |
| 1395 { | |
| 1396 /* Unmap pages at the end of the region. */ | |
| 1397 nbytes = - npages * page_size; | |
| 1398 if (munmap (region_end - nbytes, nbytes) == -1) | |
| 1399 fprintf (stderr, "munmap: %s\n", emacs_strerror (errno)); | |
| 1400 else | |
| 1401 { | |
| 1402 r->nbytes_mapped -= nbytes; | |
| 1403 success = 1; | |
| 1404 } | |
| 1405 } | |
| 1406 else if (npages > 0) | |
| 1407 { | |
| 1408 struct mmap_region *r2; | |
| 1409 | |
| 1410 nbytes = npages * page_size; | |
| 1411 | |
| 1412 /* Try to map additional pages at the end of the region. We | |
| 1413 cannot do this if the address range is already occupied by | |
| 1414 something else because mmap deletes any previous mapping. | |
| 1415 I'm not sure this is worth doing, let's see. */ | |
| 1416 r2 = mmap_find (region_end, region_end + nbytes); | |
| 1417 if (r2 == NULL) | |
| 1418 { | |
| 1419 POINTER_TYPE *p; | |
| 1420 | |
| 1421 p = mmap (region_end, nbytes, PROT_READ | PROT_WRITE, | |
| 1422 MAP_ANON | MAP_PRIVATE | MAP_FIXED, mmap_fd, 0); | |
| 1423 if (p == MAP_FAILED) | |
| 1424 fprintf (stderr, "mmap: %s\n", emacs_strerror (errno)); | |
| 1425 else if (p != (POINTER_TYPE *) region_end) | |
| 1426 { | |
| 1427 /* Kernels are free to choose a different address. In | |
| 1428 that case, unmap what we've mapped above; we have | |
| 1429 no use for it. */ | |
| 1430 if (munmap (p, nbytes) == -1) | |
| 1431 fprintf (stderr, "munmap: %s\n", emacs_strerror (errno)); | |
| 1432 } | |
| 1433 else | |
| 1434 { | |
| 1435 r->nbytes_mapped += nbytes; | |
| 1436 success = 1; | |
| 1437 } | |
| 1438 } | |
| 1439 } | |
| 1440 | |
| 1441 return success; | |
| 1442 } | |
| 1443 | |
| 1444 | |
| 1445 /* Set or reset variables holding references to mapped regions. If | |
| 1446 RESTORE_P is zero, set all variables to null. If RESTORE_P is | |
| 1447 non-zero, set all variables to the start of the user-areas | |
| 1448 of mapped regions. | |
| 1449 | |
| 1450 This function is called from Fdump_emacs to ensure that the dumped | |
| 1451 Emacs doesn't contain references to memory that won't be mapped | |
| 1452 when Emacs starts. */ | |
| 1453 | |
| 1454 void | |
| 1455 mmap_set_vars (restore_p) | |
| 1456 int restore_p; | |
| 1457 { | |
| 1458 struct mmap_region *r; | |
| 1459 | |
| 1460 if (restore_p) | |
| 1461 { | |
| 1462 mmap_regions = mmap_regions_1; | |
| 1463 mmap_fd = mmap_fd_1; | |
| 1464 for (r = mmap_regions; r; r = r->next) | |
| 1465 *r->var = MMAP_USER_AREA (r); | |
| 1466 } | |
| 1467 else | |
| 1468 { | |
| 1469 for (r = mmap_regions; r; r = r->next) | |
| 1470 *r->var = NULL; | |
| 1471 mmap_regions_1 = mmap_regions; | |
| 1472 mmap_regions = NULL; | |
| 1473 mmap_fd_1 = mmap_fd; | |
| 1474 mmap_fd = -1; | |
| 1475 } | |
| 1476 } | |
| 1477 | |
| 1478 | |
| 1479 /* Return total number of bytes mapped. */ | |
| 1480 | |
| 1481 size_t | |
| 1482 mmap_mapped_bytes () | |
| 1483 { | |
| 1484 struct mmap_region *r; | |
| 1485 size_t n = 0; | |
| 1486 | |
| 1487 for (r = mmap_regions; r; r = r->next) | |
| 1488 n += r->nbytes_mapped; | |
| 1489 | |
| 1490 return n; | |
| 1491 } | |
| 1492 | |
| 1493 | |
| 1494 /* Allocate a block of storage large enough to hold NBYTES bytes of | |
| 1495 data. A pointer to the data is returned in *VAR. VAR is thus the | |
| 1496 address of some variable which will use the data area. | |
| 1497 | |
| 1498 The allocation of 0 bytes is valid. | |
| 1499 | |
| 1500 If we can't allocate the necessary memory, set *VAR to null, and | |
| 1501 return null. */ | |
| 1502 | |
| 1503 POINTER_TYPE * | |
| 1504 r_alloc (var, nbytes) | |
| 1505 POINTER_TYPE **var; | |
| 1506 size_t nbytes; | |
| 1507 { | |
| 1508 void *p; | |
| 1509 size_t map; | |
| 1510 | |
| 1511 r_alloc_init (); | |
| 1512 | |
| 1513 map = ROUND (nbytes + MMAP_REGION_STRUCT_SIZE, page_size); | |
| 1514 p = mmap (NULL, map, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, | |
| 1515 mmap_fd, 0); | |
| 1516 | |
| 1517 if (p == MAP_FAILED) | |
| 1518 { | |
| 1519 if (errno != ENOMEM) | |
| 1520 fprintf (stderr, "mmap: %s\n", emacs_strerror (errno)); | |
| 1521 p = NULL; | |
| 1522 } | |
| 1523 else | |
| 1524 { | |
| 1525 struct mmap_region *r = (struct mmap_region *) p; | |
| 1526 | |
| 1527 r->nbytes_specified = nbytes; | |
| 1528 r->nbytes_mapped = map; | |
| 1529 r->var = var; | |
| 1530 r->prev = NULL; | |
| 1531 r->next = mmap_regions; | |
| 1532 if (r->next) | |
| 1533 r->next->prev = r; | |
| 1534 mmap_regions = r; | |
| 1535 | |
| 1536 p = MMAP_USER_AREA (p); | |
| 1537 } | |
| 1538 | |
| 1539 return *var = p; | |
| 1540 } | |
| 1541 | |
| 1542 | |
| 1543 /* Given a pointer at address VAR to data allocated with r_alloc, | |
| 1544 resize it to size NBYTES. Change *VAR to reflect the new block, | |
| 1545 and return this value. If more memory cannot be allocated, then | |
| 1546 leave *VAR unchanged, and return null. */ | |
| 1547 | |
| 1548 POINTER_TYPE * | |
| 1549 r_re_alloc (var, nbytes) | |
| 1550 POINTER_TYPE **var; | |
| 1551 size_t nbytes; | |
| 1552 { | |
| 1553 POINTER_TYPE *result; | |
| 1554 | |
| 1555 r_alloc_init (); | |
| 1556 | |
| 1557 if (*var == NULL) | |
| 1558 result = r_alloc (var, nbytes); | |
| 1559 else if (nbytes == 0) | |
| 1560 { | |
| 1561 r_alloc_free (var); | |
| 1562 result = r_alloc (var, nbytes); | |
| 1563 } | |
| 1564 else | |
| 1565 { | |
| 1566 struct mmap_region *r = MMAP_REGION (*var); | |
| 1567 size_t room = r->nbytes_mapped - MMAP_REGION_STRUCT_SIZE; | |
| 1568 | |
| 1569 if (room < nbytes) | |
| 1570 { | |
| 1571 /* Must enlarge. */ | |
| 1572 POINTER_TYPE *old_ptr = *var; | |
| 1573 | |
| 1574 /* Try to map additional pages at the end of the region. | |
| 1575 If that fails, allocate a new region, copy data | |
| 1576 from the old region, then free it. */ | |
| 1577 if (mmap_enlarge (r, ROUND (nbytes - room, page_size) / page_size)) | |
| 1578 { | |
| 1579 r->nbytes_specified = nbytes; | |
| 1580 *var = result = old_ptr; | |
| 1581 } | |
| 1582 else if (r_alloc (var, nbytes)) | |
| 1583 { | |
| 1584 bcopy (old_ptr, *var, r->nbytes_specified); | |
| 1585 mmap_free (MMAP_REGION (old_ptr)); | |
| 1586 result = *var; | |
| 1587 r = MMAP_REGION (result); | |
| 1588 r->nbytes_specified = nbytes; | |
| 1589 } | |
| 1590 else | |
| 1591 { | |
| 1592 *var = old_ptr; | |
| 1593 result = NULL; | |
| 1594 } | |
| 1595 } | |
| 1596 else if (room - nbytes >= page_size) | |
| 1597 { | |
| 1598 /* Shrinking by at least a page. Let's give some | |
| 1599 memory back to the system. */ | |
| 1600 mmap_enlarge (r, - (room - nbytes) / page_size); | |
| 1601 result = *var; | |
| 1602 r->nbytes_specified = nbytes; | |
| 1603 } | |
| 1604 else | |
| 1605 { | |
| 1606 /* Leave it alone. */ | |
| 1607 result = *var; | |
| 1608 r->nbytes_specified = nbytes; | |
| 1609 } | |
| 1610 } | |
| 1611 | |
| 1612 return result; | |
| 1613 } | |
| 1614 | |
| 1615 | |
| 1616 /* Free a block of relocatable storage whose data is pointed to by | |
| 1617 PTR. Store 0 in *PTR to show there's no block allocated. */ | |
| 1618 | |
| 1619 void | |
| 1620 r_alloc_free (var) | |
| 1621 POINTER_TYPE **var; | |
| 1622 { | |
| 1623 r_alloc_init (); | |
| 1624 | |
| 1625 if (*var) | |
| 1626 { | |
| 1627 mmap_free (MMAP_REGION (*var)); | |
| 1628 *var = NULL; | |
| 1629 } | |
| 1630 } | |
| 1631 | |
| 1632 #endif /* REL_ALLOC_MMAP */ | |
| 1633 | |
| 1634 | 1219 |
| 1635 | 1220 |
| 1636 /*********************************************************************** | 1221 /*********************************************************************** |
| 1637 Initialization | 1222 Initialization |
| 1638 ***********************************************************************/ | 1223 ***********************************************************************/ |
| 1648 /* Initialize various things for memory allocation. */ | 1233 /* Initialize various things for memory allocation. */ |
| 1649 | 1234 |
| 1650 static void | 1235 static void |
| 1651 r_alloc_init () | 1236 r_alloc_init () |
| 1652 { | 1237 { |
| 1653 #if defined REL_ALLOC_MMAP && MAP_ANON == 0 | |
| 1654 /* The value of mmap_fd is initially 0 in temacs, and -1 | |
| 1655 in a dumped Emacs. */ | |
| 1656 if (mmap_fd <= 0) | |
| 1657 { | |
| 1658 /* No anonymous mmap -- we need the file descriptor. */ | |
| 1659 mmap_fd = open ("/dev/zero", O_RDONLY); | |
| 1660 if (mmap_fd == -1) | |
| 1661 fatal ("Cannot open /dev/zero: %s", emacs_strerror (errno)); | |
| 1662 } | |
| 1663 #endif /* REL_ALLOC_MMAP && MAP_ANON == 0 */ | |
| 1664 | |
| 1665 if (r_alloc_initialized) | 1238 if (r_alloc_initialized) |
| 1666 return; | 1239 return; |
| 1667 r_alloc_initialized = 1; | 1240 r_alloc_initialized = 1; |
| 1668 #if defined REL_ALLOC_MMAP && MAP_ANON != 0 | |
| 1669 mmap_fd = -1; | |
| 1670 #endif | |
| 1671 | 1241 |
| 1672 page_size = PAGE; | 1242 page_size = PAGE; |
| 1673 #ifndef SYSTEM_MALLOC | 1243 #ifndef SYSTEM_MALLOC |
| 1674 real_morecore = __morecore; | 1244 real_morecore = __morecore; |
| 1675 __morecore = r_alloc_sbrk; | 1245 __morecore = r_alloc_sbrk; |
