aboutsummaryrefslogtreecommitdiffstats
path: root/src/ralloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ralloc.c')
-rw-r--r--src/ralloc.c430
1 files changed, 0 insertions, 430 deletions
diff --git a/src/ralloc.c b/src/ralloc.c
index 9858e45a87e..d61c59a253b 100644
--- a/src/ralloc.c
+++ b/src/ralloc.c
@@ -926,7 +926,6 @@ r_alloc_sbrk (size)
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
@@ -1217,420 +1216,6 @@ r_alloc_check ()
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
1265struct 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
1284static 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
1289static int mmap_fd;
1290
1291/* Temporary storage for mmap_set_vars, see there. */
1292
1293static struct mmap_region *mmap_regions_1;
1294static 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
1319static int mmap_free P_ ((struct mmap_region *));
1320static int mmap_enlarge P_ ((struct mmap_region *, int));
1321static struct mmap_region *mmap_find P_ ((POINTER_TYPE *, POINTER_TYPE *));
1322POINTER_TYPE *r_alloc P_ ((POINTER_TYPE **, size_t));
1323POINTER_TYPE *r_re_alloc P_ ((POINTER_TYPE **, size_t));
1324void 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
1331static struct mmap_region *
1332mmap_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
1361static int
1362mmap_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
1385static int
1386mmap_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
1454void
1455mmap_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
1481size_t
1482mmap_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
1503POINTER_TYPE *
1504r_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
1548POINTER_TYPE *
1549r_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
1619void
1620r_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/***********************************************************************
@@ -1650,24 +1235,9 @@ extern POINTER (*__morecore) ();
1650static void 1235static void
1651r_alloc_init () 1236r_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