3051 uintptr_t res = (uintptr_t) ::mmap(addr, size, PROT_NONE, |
3051 uintptr_t res = (uintptr_t) ::mmap(addr, size, PROT_NONE, |
3052 MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0); |
3052 MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0); |
3053 return res != (uintptr_t) MAP_FAILED; |
3053 return res != (uintptr_t) MAP_FAILED; |
3054 } |
3054 } |
3055 |
3055 |
3056 // If there is no page mapped/committed, top (bottom + size) is returned |
3056 static address get_stack_commited_bottom(address bottom, size_t size) { |
3057 static address get_stack_mapped_bottom(address bottom, |
3057 address nbot = bottom; |
3058 size_t size, |
3058 address ntop = bottom + size; |
3059 bool committed_only /* must have backing pages */) { |
3059 |
3060 // address used to test if the page is mapped/committed |
|
3061 address test_addr = bottom + size; |
|
3062 size_t page_sz = os::vm_page_size(); |
3060 size_t page_sz = os::vm_page_size(); |
3063 unsigned pages = size / page_sz; |
3061 unsigned pages = size / page_sz; |
3064 |
3062 |
3065 unsigned char vec[1]; |
3063 unsigned char vec[1]; |
3066 unsigned imin = 1, imax = pages + 1, imid; |
3064 unsigned imin = 1, imax = pages + 1, imid; |
3068 |
3066 |
3069 assert(imin <= imax, "Unexpected page size"); |
3067 assert(imin <= imax, "Unexpected page size"); |
3070 |
3068 |
3071 while (imin < imax) { |
3069 while (imin < imax) { |
3072 imid = (imax + imin) / 2; |
3070 imid = (imax + imin) / 2; |
3073 test_addr = bottom + (imid * page_sz); |
3071 nbot = ntop - (imid * page_sz); |
3074 |
3072 |
3075 // Use a trick with mincore to check whether the page is mapped or not. |
3073 // Use a trick with mincore to check whether the page is mapped or not. |
3076 // mincore sets vec to 1 if page resides in memory and to 0 if page |
3074 // mincore sets vec to 1 if page resides in memory and to 0 if page |
3077 // is swapped output but if page we are asking for is unmapped |
3075 // is swapped output but if page we are asking for is unmapped |
3078 // it returns -1,ENOMEM |
3076 // it returns -1,ENOMEM |
3079 mincore_return_value = mincore(test_addr, page_sz, vec); |
3077 mincore_return_value = mincore(nbot, page_sz, vec); |
3080 |
3078 |
3081 if (mincore_return_value == -1 || (committed_only && (vec[0] & 0x01) == 0)) { |
3079 if (mincore_return_value == -1) { |
3082 // Page is not mapped/committed go up |
3080 // Page is not mapped go up |
3083 // to find first mapped/committed page |
3081 // to find first mapped page |
3084 if ((mincore_return_value == -1 && errno != EAGAIN) |
3082 if (errno != EAGAIN) { |
3085 || (committed_only && (vec[0] & 0x01) == 0)) { |
3083 assert(errno == ENOMEM, "Unexpected mincore errno"); |
3086 assert(mincore_return_value != -1 || errno == ENOMEM, "Unexpected mincore errno"); |
3084 imax = imid; |
3087 |
|
3088 imin = imid + 1; |
|
3089 } |
3085 } |
3090 } else { |
3086 } else { |
3091 // mapped/committed, go down |
3087 // Page is mapped go down |
3092 imax= imid; |
3088 // to find first not mapped page |
3093 } |
3089 imin = imid + 1; |
3094 } |
3090 } |
3095 |
3091 } |
3096 // Adjust stack bottom one page up if last checked page is not mapped/committed |
3092 |
3097 if (mincore_return_value == -1 || (committed_only && (vec[0] & 0x01) == 0)) { |
3093 nbot = nbot + page_sz; |
3098 assert(mincore_return_value != -1 || (errno != EAGAIN && errno != ENOMEM), |
3094 |
3099 "Should not get to here"); |
3095 // Adjust stack bottom one page up if last checked page is not mapped |
3100 |
3096 if (mincore_return_value == -1) { |
3101 test_addr = test_addr + page_sz; |
3097 nbot = nbot + page_sz; |
3102 } |
3098 } |
3103 |
3099 |
3104 return test_addr; |
3100 return nbot; |
3105 } |
3101 } |
|
3102 |
3106 |
3103 |
3107 // Linux uses a growable mapping for the stack, and if the mapping for |
3104 // Linux uses a growable mapping for the stack, and if the mapping for |
3108 // the stack guard pages is not removed when we detach a thread the |
3105 // the stack guard pages is not removed when we detach a thread the |
3109 // stack cannot grow beyond the pages where the stack guard was |
3106 // stack cannot grow beyond the pages where the stack guard was |
3110 // mapped. If at some point later in the process the stack expands to |
3107 // mapped. If at some point later in the process the stack expands to |
3138 uintptr_t stack_extent = (uintptr_t) os::Linux::initial_thread_stack_bottom(); |
3135 uintptr_t stack_extent = (uintptr_t) os::Linux::initial_thread_stack_bottom(); |
3139 unsigned char vec[1]; |
3136 unsigned char vec[1]; |
3140 |
3137 |
3141 if (mincore((address)stack_extent, os::vm_page_size(), vec) == -1) { |
3138 if (mincore((address)stack_extent, os::vm_page_size(), vec) == -1) { |
3142 // Fallback to slow path on all errors, including EAGAIN |
3139 // Fallback to slow path on all errors, including EAGAIN |
3143 stack_extent = (uintptr_t) get_stack_mapped_bottom(os::Linux::initial_thread_stack_bottom(), |
3140 stack_extent = (uintptr_t) get_stack_commited_bottom( |
3144 (size_t)addr - stack_extent, |
3141 os::Linux::initial_thread_stack_bottom(), |
3145 false /* committed_only */); |
3142 (size_t)addr - stack_extent); |
3146 } |
3143 } |
3147 |
3144 |
3148 if (stack_extent < (uintptr_t)addr) { |
3145 if (stack_extent < (uintptr_t)addr) { |
3149 ::munmap((void*)stack_extent, (uintptr_t)(addr - stack_extent)); |
3146 ::munmap((void*)stack_extent, (uintptr_t)(addr - stack_extent)); |
3150 } |
3147 } |
3165 if (os::is_primordial_thread()) { |
3162 if (os::is_primordial_thread()) { |
3166 return ::munmap(addr, size) == 0; |
3163 return ::munmap(addr, size) == 0; |
3167 } |
3164 } |
3168 |
3165 |
3169 return os::uncommit_memory(addr, size); |
3166 return os::uncommit_memory(addr, size); |
3170 } |
|
3171 |
|
3172 size_t os::committed_stack_size(address bottom, size_t size) { |
|
3173 address bot = get_stack_mapped_bottom(bottom, size, true /* committed_only */); |
|
3174 return size_t(bottom + size - bot); |
|
3175 } |
3167 } |
3176 |
3168 |
3177 // If 'fixed' is true, anon_mmap() will attempt to reserve anonymous memory |
3169 // If 'fixed' is true, anon_mmap() will attempt to reserve anonymous memory |
3178 // at 'requested_addr'. If there are existing memory mappings at the same |
3170 // at 'requested_addr'. If there are existing memory mappings at the same |
3179 // location, however, they will be overwritten. If 'fixed' is false, |
3171 // location, however, they will be overwritten. If 'fixed' is false, |