comparison src/buffer.c @ 31604:91e7cea32eaa

Move allocation with mmap here, from ralloc.c. Change conditional compilation on REL_ALLOC_MMAP to USE_MMAP_FOR_BUFFERS. (mmap_alloc, mmap_free, mmap_realloc) [REL_ALLOC_MMAP]: Renamed from former r_alloc_* functions in ralloc.c. (mmap_page_size, mmap_initialized_p) [REL_ALLOC_MMAP]: New variables. (MEM_ALIGN) [REL_ALLOC_MMAP]: New macro. (mmap_init) [REL_ALLOC_MMAP]: New function. (alloc_buffer_text, enlarge_buffer_text, free_buffer_text): New functions replacing macros BUFFER_ALLOC, BUFFER_REALLOC, and BUFFER_FREE.
author Gerd Moellmann <gerd@gnu.org>
date Thu, 14 Sep 2000 15:14:02 +0000
parents 9b8c5bea5e8d
children 2050f93e8cef
comparison
equal deleted inserted replaced
31603:04e50cacc23f 31604:91e7cea32eaa
174 174
175 Lisp_Object Qmodification_hooks; 175 Lisp_Object Qmodification_hooks;
176 Lisp_Object Qinsert_in_front_hooks; 176 Lisp_Object Qinsert_in_front_hooks;
177 Lisp_Object Qinsert_behind_hooks; 177 Lisp_Object Qinsert_behind_hooks;
178 178
179 static void alloc_buffer_text P_ ((struct buffer *, size_t));
180 static void free_buffer_text P_ ((struct buffer *b));
181
182
179 /* For debugging; temporary. See set_buffer_internal. */ 183 /* For debugging; temporary. See set_buffer_internal. */
180 /* Lisp_Object Qlisp_mode, Vcheck_symbol; */ 184 /* Lisp_Object Qlisp_mode, Vcheck_symbol; */
181 185
182 void 186 void
183 nsberror (spec) 187 nsberror (spec)
345 349
346 BUF_GAP_SIZE (b) = 20; 350 BUF_GAP_SIZE (b) = 20;
347 BLOCK_INPUT; 351 BLOCK_INPUT;
348 /* We allocate extra 1-byte at the tail and keep it always '\0' for 352 /* We allocate extra 1-byte at the tail and keep it always '\0' for
349 anchoring a search. */ 353 anchoring a search. */
350 BUFFER_ALLOC (BUF_BEG_ADDR (b), (BUF_GAP_SIZE (b) + 1)); 354 alloc_buffer_text (b, BUF_GAP_SIZE (b) + 1);
351 UNBLOCK_INPUT; 355 UNBLOCK_INPUT;
352 if (! BUF_BEG_ADDR (b)) 356 if (! BUF_BEG_ADDR (b))
353 buffer_memory_full (); 357 buffer_memory_full ();
354 358
355 BUF_PT (b) = 1; 359 BUF_PT (b) = 1;
1299 1303
1300 b->name = Qnil; 1304 b->name = Qnil;
1301 1305
1302 BLOCK_INPUT; 1306 BLOCK_INPUT;
1303 if (! b->base_buffer) 1307 if (! b->base_buffer)
1304 BUFFER_FREE (BUF_BEG_ADDR (b)); 1308 free_buffer_text (b);
1305 1309
1306 if (b->newline_cache) 1310 if (b->newline_cache)
1307 { 1311 {
1308 free_region_cache (b->newline_cache); 1312 free_region_cache (b->newline_cache);
1309 b->newline_cache = 0; 1313 b->newline_cache = 0;
1546 { 1550 {
1547 register struct buffer *old_buf; 1551 register struct buffer *old_buf;
1548 register Lisp_Object tail, valcontents; 1552 register Lisp_Object tail, valcontents;
1549 Lisp_Object tem; 1553 Lisp_Object tem;
1550 1554
1551 #ifdef REL_ALLOC_MMAP 1555 #ifdef USE_MMAP_FOR_BUFFERS
1552 if (b->text->beg == NULL) 1556 if (b->text->beg == NULL)
1553 { 1557 enlarge_buffer_text (b, 0);
1554 BLOCK_INPUT; 1558 #endif /* USE_MMAP_FOR_BUFFERS */
1555 BUFFER_REALLOC (BUF_BEG_ADDR (b),
1556 (BUF_Z_BYTE (b) - BUF_BEG_BYTE (b)
1557 + BUF_GAP_SIZE (b) + 1));
1558 UNBLOCK_INPUT;
1559 }
1560 #endif /* REL_ALLOC_MMAP */
1561 1559
1562 if (current_buffer == b) 1560 if (current_buffer == b)
1563 return; 1561 return;
1564 1562
1565 old_buf = current_buffer; 1563 old_buf = current_buffer;
4059 error ("Only %s should be stored in the buffer-local variable %s", 4057 error ("Only %s should be stored in the buffer-local variable %s",
4060 type_name, XSYMBOL (sym)->name->data); 4058 type_name, XSYMBOL (sym)->name->data);
4061 } 4059 }
4062 4060
4063 4061
4062 /***********************************************************************
4063 Allocation with mmap
4064 ***********************************************************************/
4065
4066 #ifdef USE_MMAP_FOR_BUFFERS
4067
4068 #include <sys/types.h>
4069 #include <sys/mman.h>
4070
4071 #ifndef MAP_ANON
4072 #ifdef MAP_ANONYMOUS
4073 #define MAP_ANON MAP_ANONYMOUS
4074 #else
4075 #define MAP_ANON 0
4076 #endif
4077 #endif
4078
4079 #include <stdio.h>
4080 #include <errno.h>
4081
4082 #if MAP_ANON == 0
4083 #include <fcntl.h>
4084 #endif
4085
4086 #include "coding.h"
4087
4088
4089 /* Memory is allocated in regions which are mapped using mmap(2).
4090 The current implementation lets the system select mapped
4091 addresses; we're not using MAP_FIXED in general, except when
4092 trying to enlarge regions.
4093
4094 Each mapped region starts with a mmap_region structure, the user
4095 area starts after that structure, aligned to MEM_ALIGN.
4096
4097 +-----------------------+
4098 | struct mmap_info + |
4099 | padding |
4100 +-----------------------+
4101 | user data |
4102 | |
4103 | |
4104 +-----------------------+ */
4105
4106 struct mmap_region
4107 {
4108 /* User-specified size. */
4109 size_t nbytes_specified;
4110
4111 /* Number of bytes mapped */
4112 size_t nbytes_mapped;
4113
4114 /* Pointer to the location holding the address of the memory
4115 allocated with the mmap'd block. The variable actually points
4116 after this structure. */
4117 POINTER_TYPE **var;
4118
4119 /* Next and previous in list of all mmap'd regions. */
4120 struct mmap_region *next, *prev;
4121 };
4122
4123 /* Doubly-linked list of mmap'd regions. */
4124
4125 static struct mmap_region *mmap_regions;
4126
4127 /* File descriptor for mmap. If we don't have anonymous mapping,
4128 /dev/zero will be opened on it. */
4129
4130 static int mmap_fd;
4131
4132 /* Temporary storage for mmap_set_vars, see there. */
4133
4134 static struct mmap_region *mmap_regions_1;
4135 static int mmap_fd_1;
4136
4137 /* Page size on this system. */
4138
4139 static int mmap_page_size;
4140
4141 /* 1 means mmap has been intialized. */
4142
4143 static int mmap_initialized_p;
4144
4145 /* Value is X rounded up to the next multiple of N. */
4146
4147 #define ROUND(X, N) (((X) + (N) - 1) / (N) * (N))
4148
4149 /* Size of mmap_region structure plus padding. */
4150
4151 #define MMAP_REGION_STRUCT_SIZE \
4152 ROUND (sizeof (struct mmap_region), MEM_ALIGN)
4153
4154 /* Given a pointer P to the start of the user-visible part of a mapped
4155 region, return a pointer to the start of the region. */
4156
4157 #define MMAP_REGION(P) \
4158 ((struct mmap_region *) ((char *) (P) - MMAP_REGION_STRUCT_SIZE))
4159
4160 /* Given a pointer P to the start of a mapped region, return a pointer
4161 to the start of the user-visible part of the region. */
4162
4163 #define MMAP_USER_AREA(P) \
4164 ((POINTER_TYPE *) ((char *) (P) + MMAP_REGION_STRUCT_SIZE))
4165
4166 #define MEM_ALIGN sizeof (double)
4167
4168 /* Function prototypes. */
4169
4170 static int mmap_free_1 P_ ((struct mmap_region *));
4171 static int mmap_enlarge P_ ((struct mmap_region *, int));
4172 static struct mmap_region *mmap_find P_ ((POINTER_TYPE *, POINTER_TYPE *));
4173 static POINTER_TYPE *mmap_alloc P_ ((POINTER_TYPE **, size_t));
4174 static POINTER_TYPE *mmap_realloc P_ ((POINTER_TYPE **, size_t));
4175 static void mmap_free P_ ((POINTER_TYPE **ptr));
4176 static void mmap_init P_ ((void));
4177
4178
4179 /* Return a region overlapping address range START...END, or null if
4180 none. END is not including, i.e. the last byte in the range
4181 is at END - 1. */
4182
4183 static struct mmap_region *
4184 mmap_find (start, end)
4185 POINTER_TYPE *start, *end;
4186 {
4187 struct mmap_region *r;
4188 char *s = (char *) start, *e = (char *) end;
4189
4190 for (r = mmap_regions; r; r = r->next)
4191 {
4192 char *rstart = (char *) r;
4193 char *rend = rstart + r->nbytes_mapped;
4194
4195 if (/* First byte of range, i.e. START, in this region? */
4196 (s >= rstart && s < rend)
4197 /* Last byte of range, i.e. END - 1, in this region? */
4198 || (e > rstart && e <= rend)
4199 /* First byte of this region in the range? */
4200 || (rstart >= s && rstart < e)
4201 /* Last byte of this region in the range? */
4202 || (rend > s && rend <= e))
4203 break;
4204 }
4205
4206 return r;
4207 }
4208
4209
4210 /* Unmap a region. P is a pointer to the start of the user-araa of
4211 the region. Value is non-zero if successful. */
4212
4213 static int
4214 mmap_free_1 (r)
4215 struct mmap_region *r;
4216 {
4217 if (r->next)
4218 r->next->prev = r->prev;
4219 if (r->prev)
4220 r->prev->next = r->next;
4221 else
4222 mmap_regions = r->next;
4223
4224 if (munmap (r, r->nbytes_mapped) == -1)
4225 {
4226 fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
4227 return 0;
4228 }
4229
4230 return 1;
4231 }
4232
4233
4234 /* Enlarge region R by NPAGES pages. NPAGES < 0 means shrink R.
4235 Value is non-zero if successful. */
4236
4237 static int
4238 mmap_enlarge (r, npages)
4239 struct mmap_region *r;
4240 int npages;
4241 {
4242 char *region_end = (char *) r + r->nbytes_mapped;
4243 size_t nbytes;
4244 int success = 0;
4245
4246 if (npages < 0)
4247 {
4248 /* Unmap pages at the end of the region. */
4249 nbytes = - npages * mmap_page_size;
4250 if (munmap (region_end - nbytes, nbytes) == -1)
4251 fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
4252 else
4253 {
4254 r->nbytes_mapped -= nbytes;
4255 success = 1;
4256 }
4257 }
4258 else if (npages > 0)
4259 {
4260 struct mmap_region *r2;
4261
4262 nbytes = npages * mmap_page_size;
4263
4264 /* Try to map additional pages at the end of the region. We
4265 cannot do this if the address range is already occupied by
4266 something else because mmap deletes any previous mapping.
4267 I'm not sure this is worth doing, let's see. */
4268 r2 = mmap_find (region_end, region_end + nbytes);
4269 if (r2 == NULL)
4270 {
4271 POINTER_TYPE *p;
4272
4273 p = mmap (region_end, nbytes, PROT_READ | PROT_WRITE,
4274 MAP_ANON | MAP_PRIVATE | MAP_FIXED, mmap_fd, 0);
4275 if (p == MAP_FAILED)
4276 fprintf (stderr, "mmap: %s\n", emacs_strerror (errno));
4277 else if (p != (POINTER_TYPE *) region_end)
4278 {
4279 /* Kernels are free to choose a different address. In
4280 that case, unmap what we've mapped above; we have
4281 no use for it. */
4282 if (munmap (p, nbytes) == -1)
4283 fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
4284 }
4285 else
4286 {
4287 r->nbytes_mapped += nbytes;
4288 success = 1;
4289 }
4290 }
4291 }
4292
4293 return success;
4294 }
4295
4296
4297 /* Set or reset variables holding references to mapped regions. If
4298 RESTORE_P is zero, set all variables to null. If RESTORE_P is
4299 non-zero, set all variables to the start of the user-areas
4300 of mapped regions.
4301
4302 This function is called from Fdump_emacs to ensure that the dumped
4303 Emacs doesn't contain references to memory that won't be mapped
4304 when Emacs starts. */
4305
4306 void
4307 mmap_set_vars (restore_p)
4308 int restore_p;
4309 {
4310 struct mmap_region *r;
4311
4312 if (restore_p)
4313 {
4314 mmap_regions = mmap_regions_1;
4315 mmap_fd = mmap_fd_1;
4316 for (r = mmap_regions; r; r = r->next)
4317 *r->var = MMAP_USER_AREA (r);
4318 }
4319 else
4320 {
4321 for (r = mmap_regions; r; r = r->next)
4322 *r->var = NULL;
4323 mmap_regions_1 = mmap_regions;
4324 mmap_regions = NULL;
4325 mmap_fd_1 = mmap_fd;
4326 mmap_fd = -1;
4327 }
4328 }
4329
4330
4331 /* Allocate a block of storage large enough to hold NBYTES bytes of
4332 data. A pointer to the data is returned in *VAR. VAR is thus the
4333 address of some variable which will use the data area.
4334
4335 The allocation of 0 bytes is valid.
4336
4337 If we can't allocate the necessary memory, set *VAR to null, and
4338 return null. */
4339
4340 static POINTER_TYPE *
4341 mmap_alloc (var, nbytes)
4342 POINTER_TYPE **var;
4343 size_t nbytes;
4344 {
4345 void *p;
4346 size_t map;
4347
4348 mmap_init ();
4349
4350 map = ROUND (nbytes + MMAP_REGION_STRUCT_SIZE, mmap_page_size);
4351 p = mmap (NULL, map, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
4352 mmap_fd, 0);
4353
4354 if (p == MAP_FAILED)
4355 {
4356 if (errno != ENOMEM)
4357 fprintf (stderr, "mmap: %s\n", emacs_strerror (errno));
4358 p = NULL;
4359 }
4360 else
4361 {
4362 struct mmap_region *r = (struct mmap_region *) p;
4363
4364 r->nbytes_specified = nbytes;
4365 r->nbytes_mapped = map;
4366 r->var = var;
4367 r->prev = NULL;
4368 r->next = mmap_regions;
4369 if (r->next)
4370 r->next->prev = r;
4371 mmap_regions = r;
4372
4373 p = MMAP_USER_AREA (p);
4374 }
4375
4376 return *var = p;
4377 }
4378
4379
4380 /* Given a pointer at address VAR to data allocated with mmap_alloc,
4381 resize it to size NBYTES. Change *VAR to reflect the new block,
4382 and return this value. If more memory cannot be allocated, then
4383 leave *VAR unchanged, and return null. */
4384
4385 static POINTER_TYPE *
4386 mmap_realloc (var, nbytes)
4387 POINTER_TYPE **var;
4388 size_t nbytes;
4389 {
4390 POINTER_TYPE *result;
4391
4392 mmap_init ();
4393
4394 if (*var == NULL)
4395 result = mmap_alloc (var, nbytes);
4396 else if (nbytes == 0)
4397 {
4398 mmap_free (var);
4399 result = mmap_alloc (var, nbytes);
4400 }
4401 else
4402 {
4403 struct mmap_region *r = MMAP_REGION (*var);
4404 size_t room = r->nbytes_mapped - MMAP_REGION_STRUCT_SIZE;
4405
4406 if (room < nbytes)
4407 {
4408 /* Must enlarge. */
4409 POINTER_TYPE *old_ptr = *var;
4410
4411 /* Try to map additional pages at the end of the region.
4412 If that fails, allocate a new region, copy data
4413 from the old region, then free it. */
4414 if (mmap_enlarge (r, (ROUND (nbytes - room, mmap_page_size)
4415 / mmap_page_size)))
4416 {
4417 r->nbytes_specified = nbytes;
4418 *var = result = old_ptr;
4419 }
4420 else if (mmap_alloc (var, nbytes))
4421 {
4422 bcopy (old_ptr, *var, r->nbytes_specified);
4423 mmap_free_1 (MMAP_REGION (old_ptr));
4424 result = *var;
4425 r = MMAP_REGION (result);
4426 r->nbytes_specified = nbytes;
4427 }
4428 else
4429 {
4430 *var = old_ptr;
4431 result = NULL;
4432 }
4433 }
4434 else if (room - nbytes >= mmap_page_size)
4435 {
4436 /* Shrinking by at least a page. Let's give some
4437 memory back to the system. */
4438 mmap_enlarge (r, - (room - nbytes) / mmap_page_size);
4439 result = *var;
4440 r->nbytes_specified = nbytes;
4441 }
4442 else
4443 {
4444 /* Leave it alone. */
4445 result = *var;
4446 r->nbytes_specified = nbytes;
4447 }
4448 }
4449
4450 return result;
4451 }
4452
4453
4454 /* Free a block of relocatable storage whose data is pointed to by
4455 PTR. Store 0 in *PTR to show there's no block allocated. */
4456
4457 static void
4458 mmap_free (var)
4459 POINTER_TYPE **var;
4460 {
4461 mmap_init ();
4462
4463 if (*var)
4464 {
4465 mmap_free_1 (MMAP_REGION (*var));
4466 *var = NULL;
4467 }
4468 }
4469
4470
4471 /* Perform necessary intializations for the use of mmap. */
4472
4473 static void
4474 mmap_init ()
4475 {
4476 #if MAP_ANON == 0
4477 /* The value of mmap_fd is initially 0 in temacs, and -1
4478 in a dumped Emacs. */
4479 if (mmap_fd <= 0)
4480 {
4481 /* No anonymous mmap -- we need the file descriptor. */
4482 mmap_fd = open ("/dev/zero", O_RDONLY);
4483 if (mmap_fd == -1)
4484 fatal ("Cannot open /dev/zero: %s", emacs_strerror (errno));
4485 }
4486 #endif /* MAP_ANON == 0 */
4487
4488 if (mmap_initialized_p)
4489 return;
4490 mmap_initialized_p = 1;
4491
4492 #if MAP_ANON != 0
4493 mmap_fd = -1;
4494 #endif
4495
4496 mmap_page_size = getpagesize ();
4497 }
4498
4499 #endif /* USE_MMAP_FOR_BUFFERS */
4500
4501
4502
4503 /***********************************************************************
4504 Buffer-text Allocation
4505 ***********************************************************************/
4506
4507 #ifdef REL_ALLOC
4508 extern POINTER_TYPE *r_alloc P_ ((POINTER_TYPE **, size_t));
4509 extern POINTER_TYPE *r_re_alloc P_ ((POINTER_TYPE **, size_t));
4510 extern void r_alloc_free P_ ((POINTER_TYPE **ptr));
4511 #endif /* REL_ALLOC */
4512
4513
4514 /* Allocate NBYTES bytes for buffer B's text buffer. */
4515
4516 static void
4517 alloc_buffer_text (b, nbytes)
4518 struct buffer *b;
4519 size_t nbytes;
4520 {
4521 POINTER_TYPE *p;
4522
4523 BLOCK_INPUT;
4524 #if defined USE_MMAP_FOR_BUFFERS
4525 p = mmap_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
4526 #elif defined REL_ALLOC
4527 p = r_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
4528 #else
4529 p = xmalloc (b->text->beg, nbytes);
4530 #endif
4531
4532 if (p == NULL)
4533 {
4534 UNBLOCK_INPUT;
4535 memory_full ();
4536 }
4537
4538 b->text->beg = (unsigned char *) p;
4539 UNBLOCK_INPUT;
4540 }
4541
4542 /* Enlarge buffer B's text buffer by DELTA bytes. DELTA < 0 means
4543 shrink it. */
4544
4545 void
4546 enlarge_buffer_text (b, delta)
4547 struct buffer *b;
4548 int delta;
4549 {
4550 POINTER_TYPE *p;
4551 size_t nbytes = (BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1
4552 + delta);
4553 BLOCK_INPUT;
4554 #if defined USE_MMAP_FOR_BUFFERS
4555 p = mmap_realloc ((POINTER_TYPE **) &b->text->beg, nbytes);
4556 #elif defined REL_ALLOC
4557 p = r_re_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
4558 #else
4559 p = xrealloc (b->text->beg, nbytes);
4560 #endif
4561
4562 if (p == NULL)
4563 {
4564 UNBLOCK_INPUT;
4565 memory_full ();
4566 }
4567
4568 BUF_BEG_ADDR (b) = (unsigned char *) p;
4569 UNBLOCK_INPUT;
4570 }
4571
4572
4573 /* Free buffer B's text buffer. */
4574
4575 static void
4576 free_buffer_text (b)
4577 struct buffer *b;
4578 {
4579 BLOCK_INPUT;
4580
4581 #if defined USE_MMAP_FOR_BUFFERS
4582 mmap_free ((POINTER_TYPE **) &b->text->beg);
4583 #elif defined REL_ALLOC
4584 r_alloc_free ((POINTER_TYPE **) &b->text->beg);
4585 #else
4586 xfree (b->text->beg);
4587 #endif
4588
4589 BUF_BEG_ADDR (b) = NULL;
4590 UNBLOCK_INPUT;
4591 }
4592
4593
4594
4595 /***********************************************************************
4596 Initialization
4597 ***********************************************************************/
4598
4064 void 4599 void
4065 init_buffer_once () 4600 init_buffer_once ()
4066 { 4601 {
4067 int idx; 4602 int idx;
4068 4603
4232 char *pwd; 4767 char *pwd;
4233 struct stat dotstat, pwdstat; 4768 struct stat dotstat, pwdstat;
4234 Lisp_Object temp; 4769 Lisp_Object temp;
4235 int rc; 4770 int rc;
4236 4771
4237 #ifdef REL_ALLOC_MMAP 4772 #ifdef USE_MMAP_FOR_BUFFERS
4238 { 4773 {
4239 /* When using the ralloc implementation based on mmap(2), buffer 4774 /* When using the ralloc implementation based on mmap(2), buffer
4240 text pointers will have been set to null in the dumped Emacs. 4775 text pointers will have been set to null in the dumped Emacs.
4241 Map new memory. */ 4776 Map new memory. */
4242 struct buffer *b; 4777 struct buffer *b;
4243 4778
4244 BLOCK_INPUT;
4245 for (b = all_buffers; b; b = b->next) 4779 for (b = all_buffers; b; b = b->next)
4246 if (b->text->beg == NULL) 4780 if (b->text->beg == NULL)
4247 BUFFER_REALLOC (BUF_BEG_ADDR (b), 4781 enlarge_buffer_text (b, 0);
4248 (BUF_Z_BYTE (b) - BUF_BEG_BYTE (b)
4249 + BUF_GAP_SIZE (b) + 1));
4250 UNBLOCK_INPUT;
4251 } 4782 }
4252 #endif /* REL_ALLOC_MMAP */ 4783 #endif /* USE_MMAP_FOR_BUFFERS */
4253 4784
4254 Fset_buffer (Fget_buffer_create (build_string ("*scratch*"))); 4785 Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
4255 if (NILP (buffer_defaults.enable_multibyte_characters)) 4786 if (NILP (buffer_defaults.enable_multibyte_characters))
4256 Fset_buffer_multibyte (Qnil); 4787 Fset_buffer_multibyte (Qnil);
4257 4788