shared_alloc_shm.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | https://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Andi Gutmans <andi@php.net> |
  16. | Zeev Suraski <zeev@php.net> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@php.net> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #include "zend_shared_alloc.h"
  22. #ifdef USE_SHM
  23. #if defined(__FreeBSD__)
  24. # include <machine/param.h>
  25. #endif
  26. #include <sys/types.h>
  27. #include <sys/shm.h>
  28. #include <sys/ipc.h>
  29. #include <signal.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <unistd.h>
  33. #include <errno.h>
  34. #include <sys/stat.h>
  35. #include <fcntl.h>
  36. #ifndef MIN
  37. # define MIN(x, y) ((x) > (y)? (y) : (x))
  38. #endif
  39. #define SEG_ALLOC_SIZE_MAX 32*1024*1024
  40. #define SEG_ALLOC_SIZE_MIN 2*1024*1024
  41. typedef struct {
  42. zend_shared_segment common;
  43. int shm_id;
  44. } zend_shared_segment_shm;
  45. static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, char **error_in)
  46. {
  47. int i;
  48. size_t allocate_size = 0, remaining_bytes = requested_size, seg_allocate_size;
  49. int first_segment_id = -1;
  50. key_t first_segment_key = -1;
  51. struct shmid_ds sds;
  52. int shmget_flags;
  53. zend_shared_segment_shm *shared_segments;
  54. seg_allocate_size = SEG_ALLOC_SIZE_MAX;
  55. /* determine segment size we _really_ need:
  56. * no more than to include requested_size
  57. */
  58. while (requested_size * 2 <= seg_allocate_size && seg_allocate_size > SEG_ALLOC_SIZE_MIN) {
  59. seg_allocate_size >>= 1;
  60. }
  61. shmget_flags = IPC_CREAT|SHM_R|SHM_W|IPC_EXCL;
  62. /* try allocating this much, if not - try shrinking */
  63. while (seg_allocate_size >= SEG_ALLOC_SIZE_MIN) {
  64. allocate_size = MIN(requested_size, seg_allocate_size);
  65. first_segment_id = shmget(first_segment_key, allocate_size, shmget_flags);
  66. if (first_segment_id != -1) {
  67. break;
  68. }
  69. seg_allocate_size >>= 1; /* shrink the allocated block */
  70. }
  71. if (first_segment_id == -1) {
  72. *error_in = "shmget";
  73. return ALLOC_FAILURE;
  74. }
  75. *shared_segments_count = ((requested_size - 1) / seg_allocate_size) + 1;
  76. *shared_segments_p = (zend_shared_segment_shm **) calloc(1, (*shared_segments_count) * sizeof(zend_shared_segment_shm) + sizeof(void *) * (*shared_segments_count));
  77. if (!*shared_segments_p) {
  78. *error_in = "calloc";
  79. return ALLOC_FAILURE;
  80. }
  81. shared_segments = (zend_shared_segment_shm *)((char *)(*shared_segments_p) + sizeof(void *) * (*shared_segments_count));
  82. for (i = 0; i < *shared_segments_count; i++) {
  83. (*shared_segments_p)[i] = shared_segments + i;
  84. }
  85. remaining_bytes = requested_size;
  86. for (i = 0; i < *shared_segments_count; i++) {
  87. allocate_size = MIN(remaining_bytes, seg_allocate_size);
  88. if (i != 0) {
  89. shared_segments[i].shm_id = shmget(IPC_PRIVATE, allocate_size, shmget_flags);
  90. } else {
  91. shared_segments[i].shm_id = first_segment_id;
  92. }
  93. if (shared_segments[i].shm_id == -1) {
  94. return ALLOC_FAILURE;
  95. }
  96. shared_segments[i].common.p = shmat(shared_segments[i].shm_id, NULL, 0);
  97. if (shared_segments[i].common.p == (void *)-1) {
  98. *error_in = "shmat";
  99. shmctl(shared_segments[i].shm_id, IPC_RMID, &sds);
  100. return ALLOC_FAILURE;
  101. }
  102. shmctl(shared_segments[i].shm_id, IPC_RMID, &sds);
  103. shared_segments[i].common.pos = 0;
  104. shared_segments[i].common.size = allocate_size;
  105. remaining_bytes -= allocate_size;
  106. }
  107. return ALLOC_SUCCESS;
  108. }
  109. static int detach_segment(zend_shared_segment_shm *shared_segment)
  110. {
  111. shmdt(shared_segment->common.p);
  112. return 0;
  113. }
  114. static size_t segment_type_size(void)
  115. {
  116. return sizeof(zend_shared_segment_shm);
  117. }
  118. zend_shared_memory_handlers zend_alloc_shm_handlers = {
  119. (create_segments_t)create_segments,
  120. (detach_segment_t)detach_segment,
  121. segment_type_size
  122. };
  123. #endif /* USE_SHM */