ZendAccelerator.c 91 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2016 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. | http://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@zend.com> |
  16. | Zeev Suraski <zeev@zend.com> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@zend.com> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #include "main/php.h"
  22. #include "main/php_globals.h"
  23. #include "zend.h"
  24. #include "zend_extensions.h"
  25. #include "zend_compile.h"
  26. #include "ZendAccelerator.h"
  27. #include "zend_persist.h"
  28. #include "zend_shared_alloc.h"
  29. #include "zend_accelerator_module.h"
  30. #include "zend_accelerator_blacklist.h"
  31. #include "zend_list.h"
  32. #include "zend_execute.h"
  33. #include "main/SAPI.h"
  34. #include "main/php_streams.h"
  35. #include "main/php_open_temporary_file.h"
  36. #include "zend_API.h"
  37. #include "zend_ini.h"
  38. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  39. # include "zend_virtual_cwd.h"
  40. #else
  41. # include "TSRM/tsrm_virtual_cwd.h"
  42. #endif
  43. #include "zend_accelerator_util_funcs.h"
  44. #include "zend_accelerator_hash.h"
  45. #ifndef ZEND_WIN32
  46. #include <netdb.h>
  47. #endif
  48. #ifdef ZEND_WIN32
  49. typedef int uid_t;
  50. typedef int gid_t;
  51. #include <io.h>
  52. #endif
  53. #ifndef ZEND_WIN32
  54. # include <sys/time.h>
  55. #else
  56. # include <process.h>
  57. #endif
  58. #ifdef HAVE_UNISTD_H
  59. # include <unistd.h>
  60. #endif
  61. #include <fcntl.h>
  62. #include <signal.h>
  63. #include <time.h>
  64. #ifndef ZEND_WIN32
  65. # include <sys/types.h>
  66. # include <sys/ipc.h>
  67. #endif
  68. #include <sys/stat.h>
  69. #include <errno.h>
  70. #define SHM_PROTECT() \
  71. do { \
  72. if (ZCG(accel_directives).protect_memory) { \
  73. zend_accel_shared_protect(1 TSRMLS_CC); \
  74. } \
  75. } while (0)
  76. #define SHM_UNPROTECT() \
  77. do { \
  78. if (ZCG(accel_directives).protect_memory) { \
  79. zend_accel_shared_protect(0 TSRMLS_CC); \
  80. } \
  81. } while (0)
  82. ZEND_EXTENSION();
  83. #ifndef ZTS
  84. zend_accel_globals accel_globals;
  85. #else
  86. int accel_globals_id;
  87. #endif
  88. /* Points to the structure shared across all PHP processes */
  89. zend_accel_shared_globals *accel_shared_globals = NULL;
  90. /* true globals, no need for thread safety */
  91. zend_bool accel_startup_ok = 0;
  92. static char *zps_failure_reason = NULL;
  93. char *zps_api_failure_reason = NULL;
  94. static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
  95. static int (*accelerator_orig_zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC);
  96. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  97. static char *(*accelerator_orig_zend_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
  98. #endif
  99. static void (*orig_chdir)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
  100. static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
  101. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  102. static char *accel_php_resolve_path(const char *filename, int filename_length, const char *path TSRMLS_DC);
  103. #endif
  104. #ifdef ZEND_WIN32
  105. # define INCREMENT(v) InterlockedIncrement(&ZCSG(v))
  106. # define DECREMENT(v) InterlockedDecrement(&ZCSG(v))
  107. # define LOCKVAL(v) (ZCSG(v))
  108. #endif
  109. #ifdef ZEND_WIN32
  110. static time_t zend_accel_get_time(void)
  111. {
  112. FILETIME now;
  113. GetSystemTimeAsFileTime(&now);
  114. return (time_t) ((((((__int64)now.dwHighDateTime) << 32)|now.dwLowDateTime) - 116444736000000000L)/10000000);
  115. }
  116. #else
  117. # define zend_accel_get_time() time(NULL)
  118. #endif
  119. static inline int is_stream_path(const char *filename)
  120. {
  121. const char *p;
  122. for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
  123. return ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/'));
  124. }
  125. static inline int is_cacheable_stream_path(const char *filename)
  126. {
  127. return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
  128. memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
  129. }
  130. /* O+ overrides PHP chdir() function and remembers the current working directory
  131. * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
  132. * avoid getcwd() call.
  133. */
  134. static ZEND_FUNCTION(accel_chdir)
  135. {
  136. char cwd[MAXPATHLEN];
  137. orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  138. if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
  139. if (ZCG(cwd)) {
  140. efree(ZCG(cwd));
  141. }
  142. ZCG(cwd_len) = strlen(cwd);
  143. ZCG(cwd) = estrndup(cwd, ZCG(cwd_len));
  144. } else {
  145. if (ZCG(cwd)) {
  146. efree(ZCG(cwd));
  147. ZCG(cwd) = NULL;
  148. }
  149. }
  150. }
  151. static inline char* accel_getcwd(int *cwd_len TSRMLS_DC)
  152. {
  153. if (ZCG(cwd)) {
  154. *cwd_len = ZCG(cwd_len);
  155. return ZCG(cwd);
  156. } else {
  157. char cwd[MAXPATHLEN + 1];
  158. if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
  159. return NULL;
  160. }
  161. *cwd_len = ZCG(cwd_len) = strlen(cwd);
  162. ZCG(cwd) = estrndup(cwd, ZCG(cwd_len));
  163. return ZCG(cwd);
  164. }
  165. }
  166. void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason TSRMLS_DC)
  167. {
  168. if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) {
  169. zend_accel_schedule_restart(reason TSRMLS_CC);
  170. }
  171. }
  172. /* O+ tracks changes of "include_path" directive. It stores all the requested
  173. * values in ZCG(include_paths) shared hash table, current value in
  174. * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in
  175. * ZCG(include_path_key).
  176. */
  177. static ZEND_INI_MH(accel_include_path_on_modify)
  178. {
  179. int ret = orig_include_path_on_modify(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
  180. ZCG(include_path_key) = NULL;
  181. if (ret == SUCCESS) {
  182. ZCG(include_path) = new_value;
  183. if (ZCG(include_path) && *ZCG(include_path)) {
  184. ZCG(include_path_len) = new_value_length;
  185. if (ZCG(enabled) && accel_startup_ok &&
  186. (ZCG(counted) || ZCSG(accelerator_enabled))) {
  187. ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len) + 1);
  188. if (!ZCG(include_path_key) &&
  189. !zend_accel_hash_is_full(&ZCSG(include_paths))) {
  190. SHM_UNPROTECT();
  191. zend_shared_alloc_lock(TSRMLS_C);
  192. ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len) + 1);
  193. if (!ZCG(include_path_key) &&
  194. !zend_accel_hash_is_full(&ZCSG(include_paths))) {
  195. char *key;
  196. key = zend_shared_alloc(ZCG(include_path_len) + 2);
  197. if (key) {
  198. memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
  199. key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
  200. ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
  201. zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key));
  202. } else {
  203. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
  204. }
  205. }
  206. zend_shared_alloc_unlock(TSRMLS_C);
  207. SHM_PROTECT();
  208. }
  209. } else {
  210. ZCG(include_path_check) = 1;
  211. }
  212. } else {
  213. ZCG(include_path) = "";
  214. ZCG(include_path_len) = 0;
  215. }
  216. }
  217. return ret;
  218. }
  219. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  220. /* Interned strings support */
  221. static char *orig_interned_strings_start;
  222. static char *orig_interned_strings_end;
  223. static const char *(*orig_new_interned_string)(const char *str, int len, int free_src TSRMLS_DC);
  224. static void (*orig_interned_strings_snapshot)(TSRMLS_D);
  225. static void (*orig_interned_strings_restore)(TSRMLS_D);
  226. /* O+ disables creation of interned strings by regular PHP compiler, instead,
  227. * it creates interned strings in shared memory when saves a script.
  228. * Such interned strings are shared across all PHP processes
  229. */
  230. static const char *accel_new_interned_string_for_php(const char *str, int len, int free_src TSRMLS_DC)
  231. {
  232. return str;
  233. }
  234. static void accel_interned_strings_snapshot_for_php(TSRMLS_D)
  235. {
  236. }
  237. static void accel_interned_strings_restore_for_php(TSRMLS_D)
  238. {
  239. }
  240. #ifndef ZTS
  241. static void accel_interned_strings_restore_state(TSRMLS_D)
  242. {
  243. unsigned int i;
  244. for (i = 0; i < ZCSG(interned_strings).nTableSize; i++) {
  245. ZCSG(interned_strings).arBuckets[i] = ZCSG(interned_strings_saved_state).arBuckets[i];
  246. if (ZCSG(interned_strings).arBuckets[i]) {
  247. ZCSG(interned_strings).arBuckets[i]->pLast = NULL;
  248. }
  249. }
  250. ZCSG(interned_strings).pListHead = ZCSG(interned_strings_saved_state).pListHead;
  251. ZCSG(interned_strings).pListTail = ZCSG(interned_strings_saved_state).pListTail;
  252. if (ZCSG(interned_strings).pListHead) {
  253. ZCSG(interned_strings).pListHead->pListLast = NULL;
  254. }
  255. if (ZCSG(interned_strings).pListTail) {
  256. ZCSG(interned_strings).pListTail->pListNext = NULL;
  257. }
  258. ZCSG(interned_strings_top) = ZCSG(interned_strings_saved_state).top;
  259. }
  260. static void accel_interned_strings_save_state(TSRMLS_D)
  261. {
  262. ZCSG(interned_strings_saved_state).arBuckets = (Bucket**)zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(Bucket *));
  263. if (!ZCSG(interned_strings_saved_state).arBuckets) {
  264. zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
  265. }
  266. memcpy(ZCSG(interned_strings_saved_state).arBuckets, ZCSG(interned_strings).arBuckets, ZCSG(interned_strings).nTableSize * sizeof(Bucket *));
  267. ZCSG(interned_strings_saved_state).pListHead = ZCSG(interned_strings).pListHead;
  268. ZCSG(interned_strings_saved_state).pListTail = ZCSG(interned_strings).pListTail;
  269. ZCSG(interned_strings_saved_state).top = ZCSG(interned_strings_top);
  270. }
  271. #endif
  272. const char *accel_new_interned_string(const char *arKey, int nKeyLength, int free_src TSRMLS_DC)
  273. {
  274. /* for now interned strings are supported only for non-ZTS build */
  275. #ifndef ZTS
  276. ulong h;
  277. uint nIndex;
  278. Bucket *p;
  279. if (arKey >= ZCSG(interned_strings_start) && arKey < ZCSG(interned_strings_end)) {
  280. /* this is already an interned string */
  281. return arKey;
  282. }
  283. h = zend_inline_hash_func(arKey, nKeyLength);
  284. nIndex = h & ZCSG(interned_strings).nTableMask;
  285. /* check for existing interned string */
  286. p = ZCSG(interned_strings).arBuckets[nIndex];
  287. while (p != NULL) {
  288. if ((p->h == h) && (p->nKeyLength == (uint)nKeyLength)) {
  289. if (!memcmp(p->arKey, arKey, nKeyLength)) {
  290. if (free_src) {
  291. efree((char*)arKey);
  292. }
  293. return p->arKey;
  294. }
  295. }
  296. p = p->pNext;
  297. }
  298. if (ZCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >=
  299. ZCSG(interned_strings_end)) {
  300. /* no memory, return the same non-interned string */
  301. zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
  302. return arKey;
  303. }
  304. /* create new interning string in shared interned strings buffer */
  305. p = (Bucket *) ZCSG(interned_strings_top);
  306. ZCSG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength);
  307. p->arKey = (char*)(p + 1);
  308. memcpy((char*)p->arKey, arKey, nKeyLength);
  309. p->nKeyLength = nKeyLength;
  310. p->h = h;
  311. p->pData = &p->pDataPtr;
  312. p->pDataPtr = p;
  313. p->pNext = ZCSG(interned_strings).arBuckets[nIndex];
  314. p->pLast = NULL;
  315. if (p->pNext) {
  316. p->pNext->pLast = p;
  317. }
  318. ZCSG(interned_strings).arBuckets[nIndex] = p;
  319. p->pListLast = ZCSG(interned_strings).pListTail;
  320. ZCSG(interned_strings).pListTail = p;
  321. p->pListNext = NULL;
  322. if (p->pListLast != NULL) {
  323. p->pListLast->pListNext = p;
  324. }
  325. if (!ZCSG(interned_strings).pListHead) {
  326. ZCSG(interned_strings).pListHead = p;
  327. }
  328. ZCSG(interned_strings).nNumOfElements++;
  329. if (free_src) {
  330. efree((char*)arKey);
  331. }
  332. return p->arKey;
  333. #else
  334. return arKey;
  335. #endif
  336. }
  337. #ifndef ZTS
  338. /* Copy PHP interned strings from PHP process memory into the shared memory */
  339. static void accel_use_shm_interned_strings(TSRMLS_D)
  340. {
  341. Bucket *p, *q;
  342. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  343. /* empty string */
  344. CG(interned_empty_string) = accel_new_interned_string("", sizeof(""), 0 TSRMLS_CC);
  345. #endif
  346. /* function table hash keys */
  347. p = CG(function_table)->pListHead;
  348. while (p) {
  349. if (p->nKeyLength) {
  350. p->arKey = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
  351. }
  352. p = p->pListNext;
  353. }
  354. /* class table hash keys, class names, properties, methods, constants, etc */
  355. p = CG(class_table)->pListHead;
  356. while (p) {
  357. zend_class_entry *ce = (zend_class_entry*)(p->pDataPtr);
  358. if (p->nKeyLength) {
  359. p->arKey = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
  360. }
  361. if (ce->name) {
  362. ce->name = accel_new_interned_string(ce->name, ce->name_length + 1, 0 TSRMLS_CC);
  363. }
  364. q = ce->properties_info.pListHead;
  365. while (q) {
  366. zend_property_info *info = (zend_property_info*)(q->pData);
  367. if (q->nKeyLength) {
  368. q->arKey = accel_new_interned_string(q->arKey, q->nKeyLength, 0 TSRMLS_CC);
  369. }
  370. if (info->name) {
  371. info->name = accel_new_interned_string(info->name, info->name_length + 1, 0 TSRMLS_CC);
  372. }
  373. q = q->pListNext;
  374. }
  375. q = ce->function_table.pListHead;
  376. while (q) {
  377. if (q->nKeyLength) {
  378. q->arKey = accel_new_interned_string(q->arKey, q->nKeyLength, 0 TSRMLS_CC);
  379. }
  380. q = q->pListNext;
  381. }
  382. q = ce->constants_table.pListHead;
  383. while (q) {
  384. if (q->nKeyLength) {
  385. q->arKey = accel_new_interned_string(q->arKey, q->nKeyLength, 0 TSRMLS_CC);
  386. }
  387. q = q->pListNext;
  388. }
  389. p = p->pListNext;
  390. }
  391. /* constant hash keys */
  392. p = EG(zend_constants)->pListHead;
  393. while (p) {
  394. if (p->nKeyLength) {
  395. p->arKey = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
  396. }
  397. p = p->pListNext;
  398. }
  399. /* auto globals hash keys and names */
  400. p = CG(auto_globals)->pListHead;
  401. while (p) {
  402. zend_auto_global *auto_global = (zend_auto_global*)p->pData;
  403. auto_global->name = accel_new_interned_string(auto_global->name, auto_global->name_len + 1, 0 TSRMLS_CC);
  404. if (p->nKeyLength) {
  405. p->arKey = accel_new_interned_string(p->arKey, p->nKeyLength, 0 TSRMLS_CC);
  406. }
  407. p = p->pListNext;
  408. }
  409. }
  410. #endif
  411. #endif
  412. static inline void accel_restart_enter(TSRMLS_D)
  413. {
  414. #ifdef ZEND_WIN32
  415. INCREMENT(restart_in);
  416. #else
  417. # ifdef _AIX
  418. static FLOCK_STRUCTURE(restart_in_progress, F_WRLCK, SEEK_SET, 2, 1);
  419. # else
  420. static const FLOCK_STRUCTURE(restart_in_progress, F_WRLCK, SEEK_SET, 2, 1);
  421. #endif
  422. if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) {
  423. zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1): %s (%d)", strerror(errno), errno);
  424. }
  425. #endif
  426. ZCSG(restart_in_progress) = 1;
  427. }
  428. static inline void accel_restart_leave(TSRMLS_D)
  429. {
  430. #ifdef ZEND_WIN32
  431. ZCSG(restart_in_progress) = 0;
  432. DECREMENT(restart_in);
  433. #else
  434. # ifdef _AIX
  435. static FLOCK_STRUCTURE(restart_finished, F_UNLCK, SEEK_SET, 2, 1);
  436. # else
  437. static const FLOCK_STRUCTURE(restart_finished, F_UNLCK, SEEK_SET, 2, 1);
  438. # endif
  439. ZCSG(restart_in_progress) = 0;
  440. if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) {
  441. zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1): %s (%d)", strerror(errno), errno);
  442. }
  443. #endif
  444. }
  445. static inline int accel_restart_is_active(TSRMLS_D)
  446. {
  447. if (ZCSG(restart_in_progress)) {
  448. #ifndef ZEND_WIN32
  449. FLOCK_STRUCTURE(restart_check, F_WRLCK, SEEK_SET, 2, 1);
  450. if (fcntl(lock_file, F_GETLK, &restart_check) == -1) {
  451. zend_accel_error(ACCEL_LOG_DEBUG, "RestartC: %s (%d)", strerror(errno), errno);
  452. return FAILURE;
  453. }
  454. if (restart_check.l_type == F_UNLCK) {
  455. ZCSG(restart_in_progress) = 0;
  456. return 0;
  457. } else {
  458. return 1;
  459. }
  460. #else
  461. return LOCKVAL(restart_in) != 0;
  462. #endif
  463. }
  464. return 0;
  465. }
  466. /* Creates a read lock for SHM access */
  467. static inline void accel_activate_add(TSRMLS_D)
  468. {
  469. #ifdef ZEND_WIN32
  470. INCREMENT(mem_usage);
  471. #else
  472. # ifdef _AIX
  473. static FLOCK_STRUCTURE(mem_usage_lock, F_RDLCK, SEEK_SET, 1, 1);
  474. # else
  475. static const FLOCK_STRUCTURE(mem_usage_lock, F_RDLCK, SEEK_SET, 1, 1);
  476. # endif
  477. if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) {
  478. zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1): %s (%d)", strerror(errno), errno);
  479. }
  480. #endif
  481. }
  482. /* Releases a lock for SHM access */
  483. static inline void accel_deactivate_sub(TSRMLS_D)
  484. {
  485. #ifdef ZEND_WIN32
  486. if (ZCG(counted)) {
  487. DECREMENT(mem_usage);
  488. ZCG(counted) = 0;
  489. }
  490. #else
  491. # ifdef _AIX
  492. static FLOCK_STRUCTURE(mem_usage_unlock, F_UNLCK, SEEK_SET, 1, 1);
  493. # else
  494. static const FLOCK_STRUCTURE(mem_usage_unlock, F_UNLCK, SEEK_SET, 1, 1);
  495. # endif
  496. if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) {
  497. zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1): %s (%d)", strerror(errno), errno);
  498. }
  499. #endif
  500. }
  501. static inline void accel_unlock_all(TSRMLS_D)
  502. {
  503. #ifdef ZEND_WIN32
  504. accel_deactivate_sub(TSRMLS_C);
  505. #else
  506. # ifdef _AIX
  507. static FLOCK_STRUCTURE(mem_usage_unlock_all, F_UNLCK, SEEK_SET, 0, 0);
  508. # else
  509. static const FLOCK_STRUCTURE(mem_usage_unlock_all, F_UNLCK, SEEK_SET, 0, 0);
  510. # endif
  511. if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) {
  512. zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll: %s (%d)", strerror(errno), errno);
  513. }
  514. #endif
  515. }
  516. #ifndef ZEND_WIN32
  517. static inline void kill_all_lockers(struct flock *mem_usage_check)
  518. {
  519. int tries = 10;
  520. /* so that other process won't try to force while we are busy cleaning up */
  521. ZCSG(force_restart_time) = 0;
  522. while (mem_usage_check->l_pid > 0) {
  523. while (tries--) {
  524. zend_accel_error(ACCEL_LOG_WARNING, "Killed locker %d", mem_usage_check->l_pid);
  525. if (kill(mem_usage_check->l_pid, SIGKILL)) {
  526. break;
  527. }
  528. /* give it a chance to die */
  529. usleep(20000);
  530. if (kill(mem_usage_check->l_pid, 0)) {
  531. /* can't kill it */
  532. break;
  533. }
  534. usleep(10000);
  535. }
  536. if (!tries) {
  537. zend_accel_error(ACCEL_LOG_WARNING, "Can't kill %d after 10 tries!", mem_usage_check->l_pid);
  538. ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
  539. }
  540. mem_usage_check->l_type = F_WRLCK;
  541. mem_usage_check->l_whence = SEEK_SET;
  542. mem_usage_check->l_start = 1;
  543. mem_usage_check->l_len = 1;
  544. mem_usage_check->l_pid = -1;
  545. if (fcntl(lock_file, F_GETLK, mem_usage_check) == -1) {
  546. zend_accel_error(ACCEL_LOG_DEBUG, "KLockers: %s (%d)", strerror(errno), errno);
  547. break;
  548. }
  549. if (mem_usage_check->l_type == F_UNLCK || mem_usage_check->l_pid <= 0) {
  550. break;
  551. }
  552. }
  553. }
  554. #endif
  555. static inline int accel_is_inactive(TSRMLS_D)
  556. {
  557. #ifdef ZEND_WIN32
  558. if (LOCKVAL(mem_usage) == 0) {
  559. return SUCCESS;
  560. }
  561. #else
  562. FLOCK_STRUCTURE(mem_usage_check, F_WRLCK, SEEK_SET, 1, 1);
  563. mem_usage_check.l_pid = -1;
  564. if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) {
  565. zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC: %s (%d)", strerror(errno), errno);
  566. return FAILURE;
  567. }
  568. if (mem_usage_check.l_type == F_UNLCK) {
  569. return SUCCESS;
  570. }
  571. if (ZCG(accel_directives).force_restart_timeout
  572. && ZCSG(force_restart_time)
  573. && time(NULL) >= ZCSG(force_restart_time)) {
  574. zend_accel_error(ACCEL_LOG_WARNING, "Forced restart at %d (after %d seconds), locked by %d", time(NULL), ZCG(accel_directives).force_restart_timeout, mem_usage_check.l_pid);
  575. kill_all_lockers(&mem_usage_check);
  576. return FAILURE; /* next request should be able to restart it */
  577. }
  578. #endif
  579. return FAILURE;
  580. }
  581. static int zend_get_stream_timestamp(const char *filename, struct stat *statbuf TSRMLS_DC)
  582. {
  583. php_stream_wrapper *wrapper;
  584. php_stream_statbuf stream_statbuf;
  585. int ret, er;
  586. if (!filename) {
  587. return FAILURE;
  588. }
  589. wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC);
  590. if (!wrapper) {
  591. return FAILURE;
  592. }
  593. if (!wrapper->wops || !wrapper->wops->url_stat) {
  594. statbuf->st_mtime = 1;
  595. return SUCCESS; /* anything other than 0 is considered to be a valid timestamp */
  596. }
  597. er = EG(error_reporting);
  598. EG(error_reporting) = 0;
  599. zend_try {
  600. ret = wrapper->wops->url_stat(wrapper, (char*)filename, PHP_STREAM_URL_STAT_QUIET, &stream_statbuf, NULL TSRMLS_CC);
  601. } zend_catch {
  602. ret = -1;
  603. } zend_end_try();
  604. EG(error_reporting) = er;
  605. if (ret != 0) {
  606. return FAILURE;
  607. }
  608. *statbuf = stream_statbuf.sb;
  609. return SUCCESS;
  610. }
  611. #if ZEND_WIN32
  612. static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_handle, size_t *size)
  613. {
  614. static unsigned __int64 utc_base = 0;
  615. static FILETIME utc_base_ft;
  616. WIN32_FILE_ATTRIBUTE_DATA fdata;
  617. if (!file_handle->opened_path) {
  618. return 0;
  619. }
  620. if (!utc_base) {
  621. SYSTEMTIME st;
  622. st.wYear = 1970;
  623. st.wMonth = 1;
  624. st.wDay = 1;
  625. st.wHour = 0;
  626. st.wMinute = 0;
  627. st.wSecond = 0;
  628. st.wMilliseconds = 0;
  629. SystemTimeToFileTime (&st, &utc_base_ft);
  630. utc_base = (((unsigned __int64)utc_base_ft.dwHighDateTime) << 32) + utc_base_ft.dwLowDateTime;
  631. }
  632. if (GetFileAttributesEx(file_handle->opened_path, GetFileExInfoStandard, &fdata) != 0) {
  633. unsigned __int64 ftime;
  634. if (CompareFileTime (&fdata.ftLastWriteTime, &utc_base_ft) < 0) {
  635. return 0;
  636. }
  637. ftime = (((unsigned __int64)fdata.ftLastWriteTime.dwHighDateTime) << 32) + fdata.ftLastWriteTime.dwLowDateTime - utc_base;
  638. ftime /= 10000000L;
  639. if (size) {
  640. *size = (size_t)(((unsigned __int64)fdata.nFileSizeHigh) << 32 + (unsigned __int64)fdata.nFileSizeLow);
  641. }
  642. return (accel_time_t)ftime;
  643. }
  644. return 0;
  645. }
  646. #endif
  647. static accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size TSRMLS_DC)
  648. {
  649. struct stat statbuf;
  650. #ifdef ZEND_WIN32
  651. accel_time_t res;
  652. #endif
  653. if (sapi_module.get_stat &&
  654. !EG(opline_ptr) &&
  655. file_handle->filename == SG(request_info).path_translated) {
  656. struct stat *tmpbuf = sapi_module.get_stat(TSRMLS_C);
  657. if (tmpbuf) {
  658. if (size) {
  659. *size = tmpbuf->st_size;
  660. }
  661. return tmpbuf->st_mtime;
  662. }
  663. }
  664. #ifdef ZEND_WIN32
  665. res = zend_get_file_handle_timestamp_win(file_handle, size);
  666. if (res) {
  667. return res;
  668. }
  669. #endif
  670. switch (file_handle->type) {
  671. case ZEND_HANDLE_FD:
  672. if (fstat(file_handle->handle.fd, &statbuf) == -1) {
  673. return 0;
  674. }
  675. break;
  676. case ZEND_HANDLE_FP:
  677. if (fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
  678. if (zend_get_stream_timestamp(file_handle->filename, &statbuf TSRMLS_CC) != SUCCESS) {
  679. return 0;
  680. }
  681. }
  682. break;
  683. case ZEND_HANDLE_FILENAME:
  684. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  685. case ZEND_HANDLE_MAPPED:
  686. #endif
  687. {
  688. char *file_path = file_handle->opened_path;
  689. if (file_path) {
  690. if (is_stream_path(file_path)) {
  691. if (zend_get_stream_timestamp(file_path, &statbuf TSRMLS_CC) == SUCCESS) {
  692. break;
  693. }
  694. }
  695. if (VCWD_STAT(file_path, &statbuf) != -1) {
  696. break;
  697. }
  698. }
  699. if (zend_get_stream_timestamp(file_handle->filename, &statbuf TSRMLS_CC) != SUCCESS) {
  700. return 0;
  701. }
  702. break;
  703. }
  704. case ZEND_HANDLE_STREAM:
  705. {
  706. php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
  707. php_stream_statbuf sb;
  708. int ret, er;
  709. if (!stream ||
  710. !stream->ops ||
  711. !stream->ops->stat) {
  712. return 0;
  713. }
  714. er = EG(error_reporting);
  715. EG(error_reporting) = 0;
  716. zend_try {
  717. ret = stream->ops->stat(stream, &sb TSRMLS_CC);
  718. } zend_catch {
  719. ret = -1;
  720. } zend_end_try();
  721. EG(error_reporting) = er;
  722. if (ret != 0) {
  723. return 0;
  724. }
  725. statbuf = sb.sb;
  726. }
  727. break;
  728. default:
  729. return 0;
  730. }
  731. if (size) {
  732. *size = statbuf.st_size;
  733. }
  734. return statbuf.st_mtime;
  735. }
  736. static inline int do_validate_timestamps(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC)
  737. {
  738. zend_file_handle ps_handle;
  739. char *full_path_ptr = NULL;
  740. /** check that the persistant script is indeed the same file we cached
  741. * (if part of the path is a symlink than it possible that the user will change it)
  742. * See bug #15140
  743. */
  744. if (file_handle->opened_path) {
  745. if (strcmp(persistent_script->full_path, file_handle->opened_path) != 0) {
  746. return FAILURE;
  747. }
  748. } else {
  749. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  750. full_path_ptr = accel_php_resolve_path(file_handle->filename, strlen(file_handle->filename), ZCG(include_path) TSRMLS_CC);
  751. #else
  752. full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename, strlen(file_handle->filename) TSRMLS_CC);
  753. #endif
  754. if (full_path_ptr && strcmp(persistent_script->full_path, full_path_ptr) != 0) {
  755. efree(full_path_ptr);
  756. return FAILURE;
  757. }
  758. file_handle->opened_path = full_path_ptr;
  759. }
  760. if (persistent_script->timestamp == 0) {
  761. if (full_path_ptr) {
  762. efree(full_path_ptr);
  763. file_handle->opened_path = NULL;
  764. }
  765. return FAILURE;
  766. }
  767. if (zend_get_file_handle_timestamp(file_handle, NULL TSRMLS_CC) == persistent_script->timestamp) {
  768. if (full_path_ptr) {
  769. efree(full_path_ptr);
  770. file_handle->opened_path = NULL;
  771. }
  772. return SUCCESS;
  773. }
  774. if (full_path_ptr) {
  775. efree(full_path_ptr);
  776. file_handle->opened_path = NULL;
  777. }
  778. ps_handle.type = ZEND_HANDLE_FILENAME;
  779. ps_handle.filename = persistent_script->full_path;
  780. ps_handle.opened_path = persistent_script->full_path;
  781. if (zend_get_file_handle_timestamp(&ps_handle, NULL TSRMLS_CC) == persistent_script->timestamp) {
  782. return SUCCESS;
  783. }
  784. return FAILURE;
  785. }
  786. int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC)
  787. {
  788. if (ZCG(accel_directives).revalidate_freq &&
  789. persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
  790. return SUCCESS;
  791. } else if (do_validate_timestamps(persistent_script, file_handle TSRMLS_CC) == FAILURE) {
  792. return FAILURE;
  793. } else {
  794. persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
  795. return SUCCESS;
  796. }
  797. }
  798. static unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
  799. {
  800. signed char *mem = (signed char*)persistent_script->mem;
  801. size_t size = persistent_script->size;
  802. size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
  803. unsigned int checksum = ADLER32_INIT;
  804. if (mem < (signed char*)persistent_script) {
  805. checksum = zend_adler32(checksum, mem, (signed char*)persistent_script - mem);
  806. size -= (signed char*)persistent_script - mem;
  807. mem += (signed char*)persistent_script - mem;
  808. }
  809. zend_adler32(checksum, mem, persistent_script_check_block_size);
  810. mem += sizeof(*persistent_script);
  811. size -= sizeof(*persistent_script);
  812. if (size > 0) {
  813. checksum = zend_adler32(checksum, mem, size);
  814. }
  815. return checksum;
  816. }
  817. /* Instead of resolving full real path name each time we need to identify file,
  818. * we create a key that consist from requested file name, current working
  819. * directory, current include_path, etc */
  820. char *accel_make_persistent_key_ex(zend_file_handle *file_handle, int path_length, int *key_len TSRMLS_DC)
  821. {
  822. int key_length;
  823. /* CWD and include_path don't matter for absolute file names and streams */
  824. if (ZCG(accel_directives).use_cwd &&
  825. !IS_ABSOLUTE_PATH(file_handle->filename, path_length) &&
  826. !is_stream_path(file_handle->filename)) {
  827. char *include_path = NULL;
  828. int include_path_len = 0;
  829. const char *parent_script = NULL;
  830. int parent_script_len = 0;
  831. int cur_len = 0;
  832. int cwd_len;
  833. char *cwd;
  834. if ((cwd = accel_getcwd(&cwd_len TSRMLS_CC)) == NULL) {
  835. /* we don't handle this well for now. */
  836. zend_accel_error(ACCEL_LOG_INFO, "getcwd() failed for '%s' (%d), please try to set opcache.use_cwd to 0 in ini file", file_handle->filename, errno);
  837. if (file_handle->opened_path) {
  838. cwd = file_handle->opened_path;
  839. cwd_len = strlen(cwd);
  840. } else {
  841. ZCG(key_len) = 0;
  842. return NULL;
  843. }
  844. }
  845. if (ZCG(include_path_key)) {
  846. include_path = ZCG(include_path_key);
  847. include_path_len = 1;
  848. } else {
  849. include_path = ZCG(include_path);
  850. include_path_len = ZCG(include_path_len);
  851. if (ZCG(include_path_check) &&
  852. ZCG(enabled) && accel_startup_ok &&
  853. (ZCG(counted) || ZCSG(accelerator_enabled)) &&
  854. !zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len) + 1) &&
  855. !zend_accel_hash_is_full(&ZCSG(include_paths))) {
  856. SHM_UNPROTECT();
  857. zend_shared_alloc_lock(TSRMLS_C);
  858. ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len) + 1);
  859. if (ZCG(include_path_key)) {
  860. include_path = ZCG(include_path_key);
  861. include_path_len = 1;
  862. } else if (!zend_accel_hash_is_full(&ZCSG(include_paths))) {
  863. char *key;
  864. key = zend_shared_alloc(ZCG(include_path_len) + 2);
  865. if (key) {
  866. memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
  867. key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
  868. ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
  869. zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key));
  870. include_path = ZCG(include_path_key);
  871. include_path_len = 1;
  872. } else {
  873. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
  874. }
  875. }
  876. zend_shared_alloc_unlock(TSRMLS_C);
  877. SHM_PROTECT();
  878. }
  879. }
  880. /* Here we add to the key the parent script directory,
  881. since fopen_wrappers from version 4.0.7 use current script's path
  882. in include path too.
  883. */
  884. if (EG(in_execution) &&
  885. (parent_script = zend_get_executed_filename(TSRMLS_C)) != NULL &&
  886. parent_script[0] != '[') {
  887. parent_script_len = strlen(parent_script);
  888. while ((--parent_script_len > 0) && !IS_SLASH(parent_script[parent_script_len]));
  889. }
  890. /* Calculate key length */
  891. key_length = cwd_len + path_length + include_path_len + 2;
  892. if (parent_script_len) {
  893. key_length += parent_script_len + 1;
  894. }
  895. /* Generate key
  896. * Note - the include_path must be the last element in the key,
  897. * since in itself, it may include colons (which we use to separate
  898. * different components of the key)
  899. */
  900. if ((size_t)key_length >= sizeof(ZCG(key))) {
  901. ZCG(key_len) = 0;
  902. return NULL;
  903. }
  904. memcpy(ZCG(key), cwd, cwd_len);
  905. ZCG(key)[cwd_len] = ':';
  906. memcpy(ZCG(key) + cwd_len + 1, file_handle->filename, path_length);
  907. ZCG(key)[cwd_len + 1 + path_length] = ':';
  908. cur_len = cwd_len + 1 + path_length + 1;
  909. if (parent_script_len) {
  910. memcpy(ZCG(key) + cur_len, parent_script, parent_script_len);
  911. cur_len += parent_script_len;
  912. ZCG(key)[cur_len] = ':';
  913. cur_len++;
  914. }
  915. memcpy(ZCG(key) + cur_len, include_path, include_path_len);
  916. ZCG(key)[key_length] = '\0';
  917. } else {
  918. /* not use_cwd */
  919. key_length = path_length;
  920. if ((size_t)key_length >= sizeof(ZCG(key))) {
  921. ZCG(key_len) = 0;
  922. return NULL;
  923. }
  924. memcpy(ZCG(key), file_handle->filename, key_length + 1);
  925. }
  926. *key_len = ZCG(key_len) = key_length;
  927. return ZCG(key);
  928. }
  929. static inline char *accel_make_persistent_key(zend_file_handle *file_handle, int *key_len TSRMLS_DC)
  930. {
  931. return accel_make_persistent_key_ex(file_handle, strlen(file_handle->filename), key_len TSRMLS_CC);
  932. }
  933. int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force TSRMLS_DC)
  934. {
  935. char *realpath;
  936. zend_persistent_script *persistent_script;
  937. if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock(TSRMLS_C) != SUCCESS) {
  938. return FAILURE;
  939. }
  940. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  941. realpath = accel_php_resolve_path(filename, filename_len, ZCG(include_path) TSRMLS_CC);
  942. #else
  943. realpath = accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
  944. #endif
  945. if (!realpath) {
  946. return FAILURE;
  947. }
  948. persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath, strlen(realpath) + 1);
  949. if (persistent_script && !persistent_script->corrupted) {
  950. zend_file_handle file_handle;
  951. file_handle.type = ZEND_HANDLE_FILENAME;
  952. file_handle.filename = realpath;
  953. file_handle.opened_path = realpath;
  954. if (force ||
  955. !ZCG(accel_directives).validate_timestamps ||
  956. do_validate_timestamps(persistent_script, &file_handle TSRMLS_CC) == FAILURE) {
  957. SHM_UNPROTECT();
  958. zend_shared_alloc_lock(TSRMLS_C);
  959. if (!persistent_script->corrupted) {
  960. persistent_script->corrupted = 1;
  961. persistent_script->timestamp = 0;
  962. ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
  963. if (ZSMMG(memory_exhausted)) {
  964. zend_accel_restart_reason reason =
  965. zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
  966. zend_accel_schedule_restart_if_necessary(reason TSRMLS_CC);
  967. }
  968. }
  969. zend_shared_alloc_unlock(TSRMLS_C);
  970. SHM_PROTECT();
  971. }
  972. }
  973. accelerator_shm_read_unlock(TSRMLS_C);
  974. efree(realpath);
  975. return SUCCESS;
  976. }
  977. /* Adds another key for existing cached script */
  978. static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_hash_entry *bucket TSRMLS_DC)
  979. {
  980. if (!zend_accel_hash_find(&ZCSG(hash), key, key_length + 1)) {
  981. if (zend_accel_hash_is_full(&ZCSG(hash))) {
  982. zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
  983. ZSMMG(memory_exhausted) = 1;
  984. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC);
  985. } else {
  986. char *new_key = zend_shared_alloc(key_length + 1);
  987. if (new_key) {
  988. memcpy(new_key, key, key_length + 1);
  989. if (zend_accel_hash_update(&ZCSG(hash), new_key, key_length + 1, 1, bucket)) {
  990. zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", new_key);
  991. }
  992. } else {
  993. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
  994. }
  995. }
  996. }
  997. }
  998. static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length, int *from_shared_memory TSRMLS_DC)
  999. {
  1000. zend_accel_hash_entry *bucket;
  1001. uint memory_used;
  1002. /* Check if script may be stored in shared memory */
  1003. if (!zend_accel_script_persistable(new_persistent_script)) {
  1004. return new_persistent_script;
  1005. }
  1006. if (!zend_accel_script_optimize(new_persistent_script TSRMLS_CC)) {
  1007. return new_persistent_script;
  1008. }
  1009. if (!compact_persistent_script(new_persistent_script)) {
  1010. return new_persistent_script;
  1011. }
  1012. /* exclusive lock */
  1013. zend_shared_alloc_lock(TSRMLS_C);
  1014. if (zend_accel_hash_is_full(&ZCSG(hash))) {
  1015. zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
  1016. ZSMMG(memory_exhausted) = 1;
  1017. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC);
  1018. zend_shared_alloc_unlock(TSRMLS_C);
  1019. return new_persistent_script;
  1020. }
  1021. /* Check if we still need to put the file into the cache (may be it was
  1022. * already stored by another process. This final check is done under
  1023. * exclusive lock) */
  1024. bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->full_path, new_persistent_script->full_path_len + 1);
  1025. if (bucket) {
  1026. zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
  1027. if (!existing_persistent_script->corrupted) {
  1028. if (!ZCG(accel_directives).revalidate_path &&
  1029. (!ZCG(accel_directives).validate_timestamps ||
  1030. (new_persistent_script->timestamp == existing_persistent_script->timestamp))) {
  1031. zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
  1032. }
  1033. zend_shared_alloc_unlock(TSRMLS_C);
  1034. return new_persistent_script;
  1035. }
  1036. }
  1037. /* Calculate the required memory size */
  1038. memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length TSRMLS_CC);
  1039. /* Allocate shared memory */
  1040. ZCG(mem) = zend_shared_alloc(memory_used);
  1041. if (!ZCG(mem)) {
  1042. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
  1043. zend_shared_alloc_unlock(TSRMLS_C);
  1044. return new_persistent_script;
  1045. }
  1046. /* cleanup after calculation */
  1047. new_persistent_script->mem = ZCG(mem);
  1048. new_persistent_script->size = memory_used;
  1049. /* Copy into shared memory */
  1050. new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length TSRMLS_CC);
  1051. /* Consistency check */
  1052. if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
  1053. zend_accel_error(
  1054. ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
  1055. "Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x\n",
  1056. new_persistent_script->full_path,
  1057. new_persistent_script->mem,
  1058. (char *)new_persistent_script->mem + new_persistent_script->size,
  1059. ZCG(mem));
  1060. }
  1061. new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
  1062. /* store script structure in the hash table */
  1063. bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->full_path, new_persistent_script->full_path_len + 1, 0, new_persistent_script);
  1064. if (bucket) {
  1065. zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", new_persistent_script->full_path);
  1066. if (!ZCG(accel_directives).revalidate_path &&
  1067. /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
  1068. memcmp(key, "phar://", sizeof("phar://") - 1) != 0 &&
  1069. (new_persistent_script->full_path_len != key_length ||
  1070. memcmp(new_persistent_script->full_path, key, key_length) != 0)) {
  1071. /* link key to the same persistent script in hash table */
  1072. if (zend_accel_hash_update(&ZCSG(hash), key, key_length + 1, 1, bucket)) {
  1073. zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", key);
  1074. } else {
  1075. zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
  1076. ZSMMG(memory_exhausted) = 1;
  1077. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC);
  1078. }
  1079. }
  1080. }
  1081. new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
  1082. zend_shared_alloc_unlock(TSRMLS_C);
  1083. *from_shared_memory = 1;
  1084. return new_persistent_script;
  1085. }
  1086. static const struct jit_auto_global_info
  1087. {
  1088. const char *name;
  1089. size_t len;
  1090. } jit_auto_globals_info[] = {
  1091. { "_SERVER", sizeof("_SERVER")},
  1092. { "_ENV", sizeof("_ENV")},
  1093. { "_REQUEST", sizeof("_REQUEST")},
  1094. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  1095. { "GLOBALS", sizeof("GLOBALS")},
  1096. #endif
  1097. };
  1098. static int zend_accel_get_auto_globals(TSRMLS_D)
  1099. {
  1100. int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
  1101. int n = 1;
  1102. int mask = 0;
  1103. for (i = 0; i < ag_size ; i++) {
  1104. if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_info[i].name, jit_auto_globals_info[i].len)) {
  1105. mask |= n;
  1106. }
  1107. n += n;
  1108. }
  1109. return mask;
  1110. }
  1111. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  1112. static int zend_accel_get_auto_globals_no_jit(TSRMLS_D)
  1113. {
  1114. if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_info[3].name, jit_auto_globals_info[3].len)) {
  1115. return 8;
  1116. }
  1117. return 0;
  1118. }
  1119. #endif
  1120. static void zend_accel_set_auto_globals(int mask TSRMLS_DC)
  1121. {
  1122. int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
  1123. int n = 1;
  1124. for (i = 0; i < ag_size ; i++) {
  1125. if (mask & n) {
  1126. zend_is_auto_global(jit_auto_globals_info[i].name, jit_auto_globals_info[i].len - 1 TSRMLS_CC);
  1127. }
  1128. n += n;
  1129. }
  1130. }
  1131. static zend_persistent_script *compile_and_cache_file(zend_file_handle *file_handle, int type, char *key, unsigned int key_length, zend_op_array **op_array_p, int *from_shared_memory TSRMLS_DC)
  1132. {
  1133. zend_persistent_script *new_persistent_script;
  1134. zend_op_array *orig_active_op_array;
  1135. HashTable *orig_function_table, *orig_class_table;
  1136. zval *orig_user_error_handler;
  1137. zend_op_array *op_array;
  1138. int do_bailout = 0;
  1139. accel_time_t timestamp = 0;
  1140. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  1141. zend_uint orig_compiler_options = 0;
  1142. #endif
  1143. /* Try to open file */
  1144. if (file_handle->type == ZEND_HANDLE_FILENAME) {
  1145. if (accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle TSRMLS_CC) == SUCCESS) {
  1146. /* key may be changed by zend_stream_open_function() */
  1147. if (key == ZCG(key)) {
  1148. key_length = ZCG(key_len);
  1149. }
  1150. } else {
  1151. *op_array_p = NULL;
  1152. if (type == ZEND_REQUIRE) {
  1153. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  1154. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
  1155. #else
  1156. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
  1157. #endif
  1158. zend_bailout();
  1159. } else {
  1160. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  1161. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
  1162. #else
  1163. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
  1164. #endif
  1165. }
  1166. return NULL;
  1167. }
  1168. }
  1169. /* check blacklist right after ensuring that file was opened */
  1170. if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, file_handle->opened_path)) {
  1171. ZCSG(blacklist_misses)++;
  1172. *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1173. return NULL;
  1174. }
  1175. if (ZCG(accel_directives).validate_timestamps ||
  1176. ZCG(accel_directives).file_update_protection ||
  1177. ZCG(accel_directives).max_file_size > 0) {
  1178. size_t size = 0;
  1179. /* Obtain the file timestamps, *before* actually compiling them,
  1180. * otherwise we have a race-condition.
  1181. */
  1182. timestamp = zend_get_file_handle_timestamp(file_handle, ZCG(accel_directives).max_file_size > 0 ? &size : NULL TSRMLS_CC);
  1183. /* If we can't obtain a timestamp (that means file is possibly socket)
  1184. * we won't cache it
  1185. */
  1186. if (timestamp == 0) {
  1187. *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1188. return NULL;
  1189. }
  1190. /* check if file is too new (may be it's not written completely yet) */
  1191. if (ZCG(accel_directives).file_update_protection &&
  1192. (ZCG(request_time) - ZCG(accel_directives).file_update_protection < timestamp)) {
  1193. *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1194. return NULL;
  1195. }
  1196. if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
  1197. ZCSG(blacklist_misses)++;
  1198. *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1199. return NULL;
  1200. }
  1201. }
  1202. new_persistent_script = create_persistent_script();
  1203. /* Save the original values for the op_array, function table and class table */
  1204. orig_active_op_array = CG(active_op_array);
  1205. orig_function_table = CG(function_table);
  1206. orig_class_table = CG(class_table);
  1207. orig_user_error_handler = EG(user_error_handler);
  1208. /* Override them with ours */
  1209. CG(function_table) = &ZCG(function_table);
  1210. EG(class_table) = CG(class_table) = &new_persistent_script->class_table;
  1211. EG(user_error_handler) = NULL;
  1212. zend_try {
  1213. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  1214. orig_compiler_options = CG(compiler_options);
  1215. CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
  1216. CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
  1217. CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
  1218. CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
  1219. #endif
  1220. op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1221. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  1222. CG(compiler_options) = orig_compiler_options;
  1223. #endif
  1224. } zend_catch {
  1225. op_array = NULL;
  1226. do_bailout = 1;
  1227. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  1228. CG(compiler_options) = orig_compiler_options;
  1229. #endif
  1230. } zend_end_try();
  1231. /* Restore originals */
  1232. CG(active_op_array) = orig_active_op_array;
  1233. CG(function_table) = orig_function_table;
  1234. EG(class_table) = CG(class_table) = orig_class_table;
  1235. EG(user_error_handler) = orig_user_error_handler;
  1236. if (!op_array) {
  1237. /* compilation failed */
  1238. free_persistent_script(new_persistent_script, 1);
  1239. zend_accel_free_user_functions(&ZCG(function_table) TSRMLS_CC);
  1240. if (do_bailout) {
  1241. zend_bailout();
  1242. }
  1243. return NULL;
  1244. }
  1245. /* Build the persistent_script structure.
  1246. Here we aren't sure we would store it, but we will need it
  1247. further anyway.
  1248. */
  1249. zend_accel_move_user_functions(&ZCG(function_table), &new_persistent_script->function_table TSRMLS_CC);
  1250. new_persistent_script->main_op_array = *op_array;
  1251. efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
  1252. /* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
  1253. will have to ping the used auto global variables before execution */
  1254. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  1255. if (PG(auto_globals_jit)) {
  1256. new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals(TSRMLS_C);
  1257. } else {
  1258. new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals_no_jit(TSRMLS_C);
  1259. }
  1260. #else
  1261. if ((PG(auto_globals_jit) && !PG(register_globals) && !PG(register_long_arrays))) {
  1262. new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals(TSRMLS_C);
  1263. }
  1264. #endif
  1265. if (ZCG(accel_directives).validate_timestamps) {
  1266. /* Obtain the file timestamps, *before* actually compiling them,
  1267. * otherwise we have a race-condition.
  1268. */
  1269. new_persistent_script->timestamp = timestamp;
  1270. new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
  1271. }
  1272. if (file_handle->opened_path) {
  1273. new_persistent_script->full_path_len = strlen(file_handle->opened_path);
  1274. new_persistent_script->full_path = estrndup(file_handle->opened_path, new_persistent_script->full_path_len);
  1275. } else {
  1276. new_persistent_script->full_path_len = strlen(file_handle->filename);
  1277. new_persistent_script->full_path = estrndup(file_handle->filename, new_persistent_script->full_path_len);
  1278. }
  1279. new_persistent_script->hash_value = zend_hash_func(new_persistent_script->full_path, new_persistent_script->full_path_len + 1);
  1280. /* Now persistent_script structure is ready in process memory */
  1281. return cache_script_in_shared_memory(new_persistent_script, key, key_length, from_shared_memory TSRMLS_CC);
  1282. }
  1283. /* zend_compile() replacement */
  1284. zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
  1285. {
  1286. zend_persistent_script *persistent_script = NULL;
  1287. char *key = NULL;
  1288. int key_length;
  1289. int from_shared_memory; /* if the script we've got is stored in SHM */
  1290. if (!file_handle->filename ||
  1291. !ZCG(enabled) || !accel_startup_ok ||
  1292. (!ZCG(counted) && !ZCSG(accelerator_enabled)) ||
  1293. CG(interactive) ||
  1294. (ZCSG(restart_in_progress) && accel_restart_is_active(TSRMLS_C)) ||
  1295. (is_stream_path(file_handle->filename) &&
  1296. !is_cacheable_stream_path(file_handle->filename))) {
  1297. /* The Accelerator is disabled, act as if without the Accelerator */
  1298. return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1299. }
  1300. /* Make sure we only increase the currently running processes semaphore
  1301. * once each execution (this function can be called more than once on
  1302. * each execution)
  1303. */
  1304. if (!ZCG(counted)) {
  1305. ZCG(counted) = 1;
  1306. accel_activate_add(TSRMLS_C);
  1307. }
  1308. /* In case this callback is called from include_once, require_once or it's
  1309. * a main FastCGI request, the key must be already calculated, and cached
  1310. * persistent script already found */
  1311. if ((EG(opline_ptr) == NULL &&
  1312. ZCG(cache_opline) == NULL &&
  1313. file_handle->filename == SG(request_info).path_translated &&
  1314. ZCG(cache_persistent_script)) ||
  1315. (EG(opline_ptr) && *EG(opline_ptr) &&
  1316. *EG(opline_ptr) == ZCG(cache_opline) &&
  1317. (*EG(opline_ptr))->opcode == ZEND_INCLUDE_OR_EVAL &&
  1318. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  1319. ((*EG(opline_ptr))->extended_value == ZEND_INCLUDE_ONCE ||
  1320. (*EG(opline_ptr))->extended_value == ZEND_REQUIRE_ONCE))) {
  1321. #else
  1322. ((*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_INCLUDE_ONCE ||
  1323. (*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_REQUIRE_ONCE))) {
  1324. #endif
  1325. if (!ZCG(key_len)) {
  1326. return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1327. }
  1328. /* persistent script was already found by overridden open() or
  1329. * resolve_path() callbacks */
  1330. persistent_script = ZCG(cache_persistent_script);
  1331. key = ZCG(key);
  1332. key_length = ZCG(key_len);
  1333. } else {
  1334. /* try to find cached script by key */
  1335. if ((key = accel_make_persistent_key(file_handle, &key_length TSRMLS_CC)) == NULL) {
  1336. return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1337. }
  1338. persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length + 1);
  1339. if (!persistent_script) {
  1340. /* try to find cached script by full real path */
  1341. zend_accel_hash_entry *bucket;
  1342. /* open file to resolve the path */
  1343. if (file_handle->type == ZEND_HANDLE_FILENAME &&
  1344. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  1345. accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle TSRMLS_CC) == FAILURE) {
  1346. #else
  1347. zend_stream_open(file_handle->filename, file_handle TSRMLS_CC) == FAILURE) {
  1348. #endif
  1349. if (type == ZEND_REQUIRE) {
  1350. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  1351. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
  1352. #else
  1353. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
  1354. #endif
  1355. zend_bailout();
  1356. } else {
  1357. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  1358. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
  1359. #else
  1360. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
  1361. #endif
  1362. }
  1363. return NULL;
  1364. }
  1365. if (file_handle->opened_path &&
  1366. (bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path, strlen(file_handle->opened_path) + 1)) != NULL) {
  1367. persistent_script = (zend_persistent_script *)bucket->data;
  1368. if (!ZCG(accel_directives).revalidate_path &&
  1369. !persistent_script->corrupted) {
  1370. SHM_UNPROTECT();
  1371. zend_shared_alloc_lock(TSRMLS_C);
  1372. zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
  1373. zend_shared_alloc_unlock(TSRMLS_C);
  1374. SHM_PROTECT();
  1375. }
  1376. }
  1377. }
  1378. }
  1379. /* clear cache */
  1380. ZCG(cache_opline) = NULL;
  1381. ZCG(cache_persistent_script) = NULL;
  1382. if (persistent_script && persistent_script->corrupted) {
  1383. persistent_script = NULL;
  1384. }
  1385. /* Revalidate acessibility of cached file */
  1386. if (EXPECTED(persistent_script != NULL) &&
  1387. UNEXPECTED(ZCG(accel_directives).validate_permission) &&
  1388. file_handle->type == ZEND_HANDLE_FILENAME &&
  1389. UNEXPECTED(access(persistent_script->full_path, R_OK) != 0)) {
  1390. if (type == ZEND_REQUIRE) {
  1391. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  1392. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
  1393. #else
  1394. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
  1395. #endif
  1396. zend_bailout();
  1397. } else {
  1398. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  1399. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
  1400. #else
  1401. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
  1402. #endif
  1403. }
  1404. return NULL;
  1405. }
  1406. SHM_UNPROTECT();
  1407. /* If script is found then validate_timestamps if option is enabled */
  1408. if (persistent_script && ZCG(accel_directives).validate_timestamps) {
  1409. if (validate_timestamp_and_record(persistent_script, file_handle TSRMLS_CC) == FAILURE) {
  1410. zend_shared_alloc_lock(TSRMLS_C);
  1411. if (!persistent_script->corrupted) {
  1412. persistent_script->corrupted = 1;
  1413. persistent_script->timestamp = 0;
  1414. ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
  1415. if (ZSMMG(memory_exhausted)) {
  1416. zend_accel_restart_reason reason =
  1417. zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
  1418. zend_accel_schedule_restart_if_necessary(reason TSRMLS_CC);
  1419. }
  1420. }
  1421. zend_shared_alloc_unlock(TSRMLS_C);
  1422. persistent_script = NULL;
  1423. }
  1424. }
  1425. /* if turned on - check the compiled script ADLER32 checksum */
  1426. if (persistent_script && ZCG(accel_directives).consistency_checks
  1427. && persistent_script->dynamic_members.hits % ZCG(accel_directives).consistency_checks == 0) {
  1428. unsigned int checksum = zend_accel_script_checksum(persistent_script);
  1429. if (checksum != persistent_script->dynamic_members.checksum ) {
  1430. /* The checksum is wrong */
  1431. zend_accel_error(ACCEL_LOG_INFO, "Checksum failed for '%s': expected=0x%0.8X, found=0x%0.8X",
  1432. persistent_script->full_path, persistent_script->dynamic_members.checksum, checksum);
  1433. zend_shared_alloc_lock(TSRMLS_C);
  1434. if (!persistent_script->corrupted) {
  1435. persistent_script->corrupted = 1;
  1436. persistent_script->timestamp = 0;
  1437. ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
  1438. if (ZSMMG(memory_exhausted)) {
  1439. zend_accel_restart_reason reason =
  1440. zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
  1441. zend_accel_schedule_restart_if_necessary(reason TSRMLS_CC);
  1442. }
  1443. }
  1444. zend_shared_alloc_unlock(TSRMLS_C);
  1445. persistent_script = NULL;
  1446. }
  1447. }
  1448. /* If script was not found or invalidated by validate_timestamps */
  1449. if (!persistent_script) {
  1450. zend_op_array *op_array;
  1451. /* Cache miss.. */
  1452. ZCSG(misses)++;
  1453. /* No memory left. Behave like without the Accelerator */
  1454. if (ZSMMG(memory_exhausted) || ZCSG(restart_pending)) {
  1455. SHM_PROTECT();
  1456. return accelerator_orig_compile_file(file_handle, type TSRMLS_CC);
  1457. }
  1458. /* Try and cache the script and assume that it is returned from_shared_memory.
  1459. * If it isn't compile_and_cache_file() changes the flag to 0
  1460. */
  1461. from_shared_memory = 0;
  1462. persistent_script = compile_and_cache_file(file_handle, type, key, key_length, &op_array, &from_shared_memory TSRMLS_CC);
  1463. /* Caching is disabled, returning op_array;
  1464. * or something went wrong during compilation, returning NULL
  1465. */
  1466. if (!persistent_script) {
  1467. SHM_PROTECT();
  1468. return op_array;
  1469. }
  1470. } else {
  1471. #if !ZEND_WIN32
  1472. ZCSG(hits)++; /* TBFixed: may lose one hit */
  1473. persistent_script->dynamic_members.hits++; /* see above */
  1474. #else
  1475. InterlockedIncrement(&ZCSG(hits));
  1476. InterlockedIncrement(&persistent_script->dynamic_members.hits);
  1477. #endif
  1478. /* see bug #15471 (old BTS) */
  1479. if (persistent_script->full_path) {
  1480. if (!EG(opline_ptr) || !*EG(opline_ptr) ||
  1481. (*EG(opline_ptr))->opcode != ZEND_INCLUDE_OR_EVAL ||
  1482. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  1483. ((*EG(opline_ptr))->extended_value != ZEND_INCLUDE_ONCE &&
  1484. (*EG(opline_ptr))->extended_value != ZEND_REQUIRE_ONCE)) {
  1485. #else
  1486. ((*EG(opline_ptr))->op2.u.constant.value.lval != ZEND_INCLUDE_ONCE &&
  1487. (*EG(opline_ptr))->op2.u.constant.value.lval != ZEND_REQUIRE_ONCE)) {
  1488. #endif
  1489. void *dummy = (void *) 1;
  1490. if (zend_hash_quick_add(&EG(included_files), persistent_script->full_path, persistent_script->full_path_len + 1, persistent_script->hash_value, &dummy, sizeof(void *), NULL) == SUCCESS) {
  1491. /* ext/phar has to load phar's metadata into memory */
  1492. if (strstr(persistent_script->full_path, ".phar") && !strstr(persistent_script->full_path, "://")) {
  1493. php_stream_statbuf ssb;
  1494. char *fname = emalloc(sizeof("phar://") + persistent_script->full_path_len);
  1495. memcpy(fname, "phar://", sizeof("phar://") - 1);
  1496. memcpy(fname + sizeof("phar://") - 1, persistent_script->full_path, persistent_script->full_path_len + 1);
  1497. php_stream_stat_path(fname, &ssb);
  1498. efree(fname);
  1499. }
  1500. }
  1501. }
  1502. }
  1503. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  1504. zend_file_handle_dtor(file_handle);
  1505. #else
  1506. zend_file_handle_dtor(file_handle TSRMLS_CC);
  1507. #endif
  1508. from_shared_memory = 1;
  1509. }
  1510. persistent_script->dynamic_members.last_used = ZCG(request_time);
  1511. SHM_PROTECT();
  1512. /* Fetch jit auto globals used in the script before execution */
  1513. if (persistent_script->ping_auto_globals_mask) {
  1514. zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask TSRMLS_CC);
  1515. }
  1516. return zend_accel_load_script(persistent_script, from_shared_memory TSRMLS_CC);
  1517. }
  1518. #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
  1519. /* Taken from php-5.2.5 because early versions don't have correct version */
  1520. static char *accel_tsrm_realpath(const char *path, int path_len TSRMLS_DC)
  1521. {
  1522. cwd_state new_state;
  1523. #if ZEND_EXTENSION_API_NO < PHP_5_6_X_API_NO
  1524. char *real_path;
  1525. #endif
  1526. char *cwd;
  1527. int cwd_len;
  1528. /* realpath("") returns CWD */
  1529. if (!*path) {
  1530. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  1531. new_state.cwd = (char*)emalloc(1);
  1532. #else
  1533. new_state.cwd = (char*)malloc(1);
  1534. if (!new_state.cwd) {
  1535. zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed");
  1536. return NULL;
  1537. }
  1538. #endif
  1539. new_state.cwd[0] = '\0';
  1540. new_state.cwd_length = 0;
  1541. if ((cwd = accel_getcwd(&cwd_len TSRMLS_CC)) != NULL) {
  1542. path = cwd;
  1543. }
  1544. } else if (!IS_ABSOLUTE_PATH(path, path_len) &&
  1545. (cwd = accel_getcwd(&cwd_len TSRMLS_CC)) != NULL) {
  1546. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  1547. new_state.cwd = estrndup(cwd, cwd_len);
  1548. #else
  1549. new_state.cwd = zend_strndup(cwd, cwd_len);
  1550. if (!new_state.cwd) {
  1551. zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed");
  1552. return NULL;
  1553. }
  1554. #endif
  1555. new_state.cwd_length = cwd_len;
  1556. } else {
  1557. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  1558. new_state.cwd = (char*)emalloc(1);
  1559. #else
  1560. new_state.cwd = (char*)malloc(1);
  1561. if (!new_state.cwd) {
  1562. zend_accel_error(ACCEL_LOG_ERROR, "malloc() failed");
  1563. return NULL;
  1564. }
  1565. #endif
  1566. new_state.cwd[0] = '\0';
  1567. new_state.cwd_length = 0;
  1568. }
  1569. #ifndef CWD_REALPATH
  1570. # define CWD_REALPATH 2
  1571. #endif
  1572. if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) {
  1573. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  1574. efree(new_state.cwd);
  1575. #else
  1576. free(new_state.cwd);
  1577. #endif
  1578. return NULL;
  1579. }
  1580. #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
  1581. return new_state.cwd;
  1582. #else
  1583. real_path = emalloc(new_state.cwd_length + 1);
  1584. memcpy(real_path, new_state.cwd, new_state.cwd_length + 1);
  1585. free(new_state.cwd);
  1586. return real_path;
  1587. #endif
  1588. }
  1589. static char *accel_php_resolve_path(const char *filename, int filename_length, const char *path TSRMLS_DC)
  1590. {
  1591. char *resolved_path;
  1592. char trypath[MAXPATHLEN];
  1593. const char *ptr, *end;
  1594. int len;
  1595. if (!filename) {
  1596. return NULL;
  1597. }
  1598. if (*filename == '.' ||
  1599. IS_ABSOLUTE_PATH(filename, filename_length) ||
  1600. !path ||
  1601. !*path) {
  1602. return accel_tsrm_realpath(filename, filename_length TSRMLS_CC);
  1603. }
  1604. ptr = path;
  1605. while (*ptr) {
  1606. for (end = ptr; *end && *end != DEFAULT_DIR_SEPARATOR; end++);
  1607. len = end - ptr;
  1608. if (*end) end++;
  1609. if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
  1610. ptr = end;
  1611. continue;
  1612. }
  1613. memcpy(trypath, ptr, len);
  1614. trypath[len] = '/';
  1615. memcpy(trypath + len + 1, filename, filename_length + 1);
  1616. ptr = end;
  1617. if ((resolved_path = accel_tsrm_realpath(trypath, len + 1 + filename_length TSRMLS_CC)) != NULL) {
  1618. return resolved_path;
  1619. }
  1620. } /* end provided path */
  1621. /* check in calling scripts' current working directory as a fall back case
  1622. */
  1623. if (EG(in_execution)) {
  1624. char *exec_fname = zend_get_executed_filename(TSRMLS_C);
  1625. int exec_fname_length = strlen(exec_fname);
  1626. while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
  1627. if (exec_fname && exec_fname[0] != '[' &&
  1628. exec_fname_length > 0 &&
  1629. exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
  1630. memcpy(trypath, exec_fname, exec_fname_length + 1);
  1631. memcpy(trypath + exec_fname_length + 1, filename, filename_length + 1);
  1632. return accel_tsrm_realpath(trypath, exec_fname_length + 1 + filename_length TSRMLS_CC);
  1633. }
  1634. }
  1635. return NULL;
  1636. }
  1637. /* zend_stream_open_function() replacement for PHP 5.2 */
  1638. static int persistent_stream_open_function(const char *filename, zend_file_handle *handle TSRMLS_DC)
  1639. {
  1640. if (ZCG(enabled) && accel_startup_ok &&
  1641. (ZCG(counted) || ZCSG(accelerator_enabled)) &&
  1642. !CG(interactive) &&
  1643. !ZCSG(restart_in_progress)) {
  1644. if (EG(opline_ptr) && *EG(opline_ptr)) {
  1645. zend_op *opline = *EG(opline_ptr);
  1646. if (opline->opcode == ZEND_INCLUDE_OR_EVAL &&
  1647. (opline->op2.u.constant.value.lval == ZEND_INCLUDE_ONCE ||
  1648. opline->op2.u.constant.value.lval == ZEND_REQUIRE_ONCE)) {
  1649. /* we are in include_once */
  1650. char *key = NULL;
  1651. int key_length;
  1652. char *resolved_path;
  1653. zend_accel_hash_entry *bucket;
  1654. zend_persistent_script *persistent_script;
  1655. int filename_len;
  1656. if (opline->op1.op_type == IS_CONST) {
  1657. filename_len = Z_STRLEN(opline->op1.u.constant);
  1658. } else {
  1659. filename_len = strlen(filename);
  1660. }
  1661. handle->filename = (char*)filename;
  1662. handle->free_filename = 0;
  1663. handle->opened_path = NULL;
  1664. /* Check if requested file already cached (by full name) */
  1665. if (IS_ABSOLUTE_PATH(filename, filename_len) &&
  1666. (persistent_script = zend_accel_hash_find(&ZCSG(hash), (char*)filename, filename_len + 1)) != NULL &&
  1667. !persistent_script->corrupted) {
  1668. handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
  1669. handle->type = ZEND_HANDLE_FILENAME;
  1670. memcpy(ZCG(key), persistent_script->full_path, persistent_script->full_path_len + 1);
  1671. ZCG(key_len) = persistent_script->full_path_len;
  1672. ZCG(cache_opline) = opline;
  1673. ZCG(cache_persistent_script) = persistent_script;
  1674. return SUCCESS;
  1675. }
  1676. /* Check if requested file already cached (by key) */
  1677. key = accel_make_persistent_key_ex(handle, filename_len, &key_length TSRMLS_CC);
  1678. if (!ZCG(accel_directives).revalidate_path &&
  1679. key &&
  1680. (persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length + 1)) != NULL &&
  1681. !persistent_script->corrupted) {
  1682. handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
  1683. handle->type = ZEND_HANDLE_FILENAME;
  1684. ZCG(cache_opline) = opline;
  1685. ZCG(cache_persistent_script) = persistent_script;
  1686. return SUCCESS;
  1687. }
  1688. /* find the full real path */
  1689. resolved_path = accel_php_resolve_path(filename, filename_len, ZCG(include_path) TSRMLS_CC);
  1690. /* Check if requested file already cached (by real name) */
  1691. if (resolved_path &&
  1692. (bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path, strlen(resolved_path) + 1)) != NULL) {
  1693. persistent_script = (zend_persistent_script *)bucket->data;
  1694. if (persistent_script && !persistent_script->corrupted) {
  1695. handle->opened_path = resolved_path;
  1696. handle->type = ZEND_HANDLE_FILENAME;
  1697. if (key && !ZCG(accel_directives).revalidate_path) {
  1698. /* add another "key" for the same bucket */
  1699. SHM_UNPROTECT();
  1700. zend_shared_alloc_lock(TSRMLS_C);
  1701. zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
  1702. zend_shared_alloc_unlock(TSRMLS_C);
  1703. SHM_PROTECT();
  1704. }
  1705. ZCG(cache_opline) = opline;
  1706. ZCG(cache_persistent_script) = persistent_script;
  1707. return SUCCESS;
  1708. }
  1709. }
  1710. if (resolved_path) {
  1711. efree(resolved_path);
  1712. }
  1713. }
  1714. }
  1715. }
  1716. ZCG(cache_opline) = NULL;
  1717. ZCG(cache_persistent_script) = NULL;
  1718. return accelerator_orig_zend_stream_open_function(filename, handle TSRMLS_CC);
  1719. }
  1720. #else
  1721. /* zend_stream_open_function() replacement for PHP 5.3 and above */
  1722. static int persistent_stream_open_function(const char *filename, zend_file_handle *handle TSRMLS_DC)
  1723. {
  1724. if (ZCG(enabled) && accel_startup_ok &&
  1725. (ZCG(counted) || ZCSG(accelerator_enabled)) &&
  1726. !CG(interactive) &&
  1727. !ZCSG(restart_in_progress)) {
  1728. /* check if callback is called from include_once or it's a main request */
  1729. if ((!EG(opline_ptr) &&
  1730. filename == SG(request_info).path_translated) ||
  1731. (EG(opline_ptr) &&
  1732. *EG(opline_ptr) &&
  1733. (*EG(opline_ptr))->opcode == ZEND_INCLUDE_OR_EVAL &&
  1734. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  1735. ((*EG(opline_ptr))->extended_value == ZEND_INCLUDE_ONCE ||
  1736. (*EG(opline_ptr))->extended_value == ZEND_REQUIRE_ONCE))) {
  1737. #else
  1738. ((*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_INCLUDE_ONCE ||
  1739. (*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_REQUIRE_ONCE))) {
  1740. #endif
  1741. /* we are in include_once or FastCGI request */
  1742. zend_persistent_script *persistent_script;
  1743. handle->filename = (char*)filename;
  1744. handle->free_filename = 0;
  1745. /* check if cached script was already found by resolve_path() */
  1746. if ((EG(opline_ptr) == NULL &&
  1747. ZCG(cache_opline) == NULL &&
  1748. ZCG(cache_persistent_script) != NULL) ||
  1749. (EG(opline_ptr) &&
  1750. (ZCG(cache_opline) == *EG(opline_ptr)))) {
  1751. persistent_script = ZCG(cache_persistent_script);
  1752. handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
  1753. handle->type = ZEND_HANDLE_FILENAME;
  1754. return SUCCESS;
  1755. #if 0
  1756. } else {
  1757. /* FIXME: It looks like this part is not needed any more */
  1758. int filename_len = strlen(filename);
  1759. if ((IS_ABSOLUTE_PATH(filename, filename_len) ||
  1760. is_stream_path(filename)) &&
  1761. (persistent_script = zend_accel_hash_find(&ZCSG(hash), (char*)filename, filename_len + 1)) != NULL &&
  1762. !persistent_script->corrupted) {
  1763. handle->opened_path = estrndup(persistent_script->full_path, persistent_script->full_path_len);
  1764. handle->type = ZEND_HANDLE_FILENAME;
  1765. memcpy(ZCG(key), persistent_script->full_path, persistent_script->full_path_len + 1);
  1766. ZCG(key_len) = persistent_script->full_path_len;
  1767. ZCG(cache_opline) = EG(opline_ptr) ? *EG(opline_ptr) : NULL;
  1768. ZCG(cache_persistent_script) = EG(opline_ptr) ? persistent_script : NULL;
  1769. return SUCCESS;
  1770. }
  1771. #endif
  1772. }
  1773. }
  1774. }
  1775. ZCG(cache_opline) = NULL;
  1776. ZCG(cache_persistent_script) = NULL;
  1777. return accelerator_orig_zend_stream_open_function(filename, handle TSRMLS_CC);
  1778. }
  1779. /* zend_resolve_path() replacement for PHP 5.3 and above */
  1780. static char* persistent_zend_resolve_path(const char *filename, int filename_len TSRMLS_DC)
  1781. {
  1782. if (ZCG(enabled) && accel_startup_ok &&
  1783. (ZCG(counted) || ZCSG(accelerator_enabled)) &&
  1784. !CG(interactive) &&
  1785. !ZCSG(restart_in_progress)) {
  1786. /* check if callback is called from include_once or it's a main request */
  1787. if ((!EG(opline_ptr) &&
  1788. filename == SG(request_info).path_translated) ||
  1789. (EG(opline_ptr) &&
  1790. *EG(opline_ptr) &&
  1791. (*EG(opline_ptr))->opcode == ZEND_INCLUDE_OR_EVAL &&
  1792. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  1793. ((*EG(opline_ptr))->extended_value == ZEND_INCLUDE_ONCE ||
  1794. (*EG(opline_ptr))->extended_value == ZEND_REQUIRE_ONCE))) {
  1795. #else
  1796. ((*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_INCLUDE_ONCE ||
  1797. (*EG(opline_ptr))->op2.u.constant.value.lval == ZEND_REQUIRE_ONCE))) {
  1798. #endif
  1799. /* we are in include_once or FastCGI request */
  1800. zend_file_handle handle;
  1801. char *key = NULL;
  1802. int key_length;
  1803. char *resolved_path;
  1804. zend_accel_hash_entry *bucket;
  1805. zend_persistent_script *persistent_script;
  1806. /* Check if requested file already cached (by full name) */
  1807. if ((IS_ABSOLUTE_PATH(filename, filename_len) ||
  1808. is_stream_path(filename)) &&
  1809. (bucket = zend_accel_hash_find_entry(&ZCSG(hash), (char*)filename, filename_len + 1)) != NULL) {
  1810. persistent_script = (zend_persistent_script *)bucket->data;
  1811. if (persistent_script && !persistent_script->corrupted) {
  1812. memcpy(ZCG(key), persistent_script->full_path, persistent_script->full_path_len + 1);
  1813. ZCG(key_len) = persistent_script->full_path_len;
  1814. ZCG(cache_opline) = EG(opline_ptr) ? *EG(opline_ptr) : NULL;
  1815. ZCG(cache_persistent_script) = persistent_script;
  1816. return estrndup(persistent_script->full_path, persistent_script->full_path_len);
  1817. }
  1818. }
  1819. /* Check if requested file already cached (by key) */
  1820. handle.filename = (char*)filename;
  1821. handle.free_filename = 0;
  1822. handle.opened_path = NULL;
  1823. key = accel_make_persistent_key_ex(&handle, filename_len, &key_length TSRMLS_CC);
  1824. if (!ZCG(accel_directives).revalidate_path &&
  1825. key &&
  1826. (persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length + 1)) != NULL &&
  1827. !persistent_script->corrupted) {
  1828. /* we have persistent script */
  1829. ZCG(cache_opline) = EG(opline_ptr) ? *EG(opline_ptr) : NULL;
  1830. ZCG(cache_persistent_script) = persistent_script;
  1831. return estrndup(persistent_script->full_path, persistent_script->full_path_len);
  1832. }
  1833. /* find the full real path */
  1834. resolved_path = accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
  1835. /* Check if requested file already cached (by real path) */
  1836. if (resolved_path &&
  1837. (bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path, strlen(resolved_path) + 1)) != NULL) {
  1838. persistent_script = (zend_persistent_script *)bucket->data;
  1839. if (persistent_script && !persistent_script->corrupted) {
  1840. if (key && !ZCG(accel_directives).revalidate_path) {
  1841. /* add another "key" for the same bucket */
  1842. SHM_UNPROTECT();
  1843. zend_shared_alloc_lock(TSRMLS_C);
  1844. zend_accel_add_key(key, key_length, bucket TSRMLS_CC);
  1845. zend_shared_alloc_unlock(TSRMLS_C);
  1846. SHM_PROTECT();
  1847. }
  1848. ZCG(cache_opline) = (EG(opline_ptr) && key) ? *EG(opline_ptr): NULL;
  1849. ZCG(cache_persistent_script) = key ? persistent_script : NULL;
  1850. return resolved_path;
  1851. }
  1852. }
  1853. ZCG(cache_opline) = NULL;
  1854. ZCG(cache_persistent_script) = NULL;
  1855. return resolved_path;
  1856. }
  1857. }
  1858. ZCG(cache_opline) = NULL;
  1859. ZCG(cache_persistent_script) = NULL;
  1860. return accelerator_orig_zend_resolve_path(filename, filename_len TSRMLS_CC);
  1861. }
  1862. #endif
  1863. static void zend_reset_cache_vars(TSRMLS_D)
  1864. {
  1865. ZSMMG(memory_exhausted) = 0;
  1866. ZCSG(hits) = 0;
  1867. ZCSG(misses) = 0;
  1868. ZCSG(blacklist_misses) = 0;
  1869. ZSMMG(wasted_shared_memory) = 0;
  1870. ZCSG(restart_pending) = 0;
  1871. ZCSG(force_restart_time) = 0;
  1872. }
  1873. static void accel_activate(void)
  1874. {
  1875. TSRMLS_FETCH();
  1876. if (!ZCG(enabled) || !accel_startup_ok) {
  1877. return;
  1878. }
  1879. #ifndef ZEND_WIN32
  1880. if (ZCG(accel_directives).validate_root) {
  1881. struct stat buf;
  1882. if (stat("/", &buf) != 0) {
  1883. ZCG(root_hash) = 0;
  1884. } else {
  1885. ZCG(root_hash) = buf.st_ino;
  1886. if (sizeof(buf.st_ino) > sizeof(ZCG(root_hash))) {
  1887. if (ZCG(root_hash) != buf.st_ino) {
  1888. zend_alter_ini_entry("opcache.enable", sizeof("opcache.enable"), "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_RUNTIME);
  1889. zend_accel_error(ACCEL_LOG_WARNING, "Can't cache files in chroot() directory with too big inode");
  1890. return;
  1891. }
  1892. }
  1893. }
  1894. } else {
  1895. ZCG(root_hash) = 0;
  1896. }
  1897. #endif
  1898. SHM_UNPROTECT();
  1899. /* PHP-5.4 and above return "double", but we use 1 sec precision */
  1900. ZCG(request_time) = (time_t)sapi_get_request_time(TSRMLS_C);
  1901. ZCG(cache_opline) = NULL;
  1902. ZCG(cache_persistent_script) = NULL;
  1903. ZCG(include_path_check) = !ZCG(include_path_key);
  1904. if (ZCG(counted)) {
  1905. #ifdef ZTS
  1906. zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %d", tsrm_thread_id());
  1907. #else
  1908. zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for pid %d", getpid());
  1909. #endif
  1910. accel_unlock_all(TSRMLS_C);
  1911. ZCG(counted) = 0;
  1912. }
  1913. if (ZCSG(restart_pending)) {
  1914. zend_shared_alloc_lock(TSRMLS_C);
  1915. if (ZCSG(restart_pending) != 0) { /* check again, to ensure that the cache wasn't already cleaned by another process */
  1916. if (accel_is_inactive(TSRMLS_C) == SUCCESS) {
  1917. zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!");
  1918. ZCSG(restart_pending) = 0;
  1919. switch ZCSG(restart_reason) {
  1920. case ACCEL_RESTART_OOM:
  1921. ZCSG(oom_restarts)++;
  1922. break;
  1923. case ACCEL_RESTART_HASH:
  1924. ZCSG(hash_restarts)++;
  1925. break;
  1926. case ACCEL_RESTART_USER:
  1927. ZCSG(manual_restarts)++;
  1928. break;
  1929. }
  1930. accel_restart_enter(TSRMLS_C);
  1931. zend_reset_cache_vars(TSRMLS_C);
  1932. zend_accel_hash_clean(&ZCSG(hash));
  1933. /* include_paths keeps only the first path */
  1934. if (ZCSG(include_paths).num_entries > 1) {
  1935. ZCSG(include_paths).num_entries = 1;
  1936. ZCSG(include_paths).num_direct_entries = 1;
  1937. memset(ZCSG(include_paths).hash_table, 0, sizeof(zend_accel_hash_entry*) * ZCSG(include_paths).max_num_entries);
  1938. ZCSG(include_paths).hash_table[zend_inline_hash_func(ZCSG(include_paths).hash_entries[0].key, ZCSG(include_paths).hash_entries[0].key_length) % ZCSG(include_paths).max_num_entries] = &ZCSG(include_paths).hash_entries[0];
  1939. }
  1940. #if (ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO) && !defined(ZTS)
  1941. if (ZCG(accel_directives).interned_strings_buffer) {
  1942. accel_interned_strings_restore_state(TSRMLS_C);
  1943. }
  1944. #endif
  1945. zend_shared_alloc_restore_state();
  1946. ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart);
  1947. ZCSG(last_restart_time) = ZCG(request_time);
  1948. accel_restart_leave(TSRMLS_C);
  1949. }
  1950. }
  1951. zend_shared_alloc_unlock(TSRMLS_C);
  1952. }
  1953. /* check if ZCG(function_table) wasn't somehow polluted on the way */
  1954. if (ZCG(internal_functions_count) != zend_hash_num_elements(&ZCG(function_table))) {
  1955. zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
  1956. }
  1957. ZCG(cwd) = NULL;
  1958. SHM_PROTECT();
  1959. }
  1960. #if !ZEND_DEBUG
  1961. /* Fast Request Shutdown
  1962. * =====================
  1963. * Zend Memory Manager frees memory by its own. We don't have to free each
  1964. * allocated block separately, but we like to call all the destructors and
  1965. * callbacks in exactly the same order.
  1966. */
  1967. static void accel_fast_hash_destroy(HashTable *ht)
  1968. {
  1969. Bucket *p = ht->pListHead;
  1970. while (p != NULL) {
  1971. ht->pDestructor(p->pData);
  1972. p = p->pListNext;
  1973. }
  1974. }
  1975. static void accel_fast_zval_ptr_dtor(zval **zval_ptr)
  1976. {
  1977. zval *zvalue = *zval_ptr;
  1978. if (Z_DELREF_P(zvalue) == 0) {
  1979. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  1980. switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
  1981. #else
  1982. switch (Z_TYPE_P(zvalue) & ~IS_CONSTANT_INDEX) {
  1983. #endif
  1984. #if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO
  1985. case IS_CONSTANT_ARRAY:
  1986. #endif
  1987. case IS_ARRAY: {
  1988. TSRMLS_FETCH();
  1989. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  1990. GC_REMOVE_ZVAL_FROM_BUFFER(zvalue);
  1991. #endif
  1992. if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table))) {
  1993. /* break possible cycles */
  1994. Z_TYPE_P(zvalue) = IS_NULL;
  1995. zvalue->value.ht->pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
  1996. accel_fast_hash_destroy(zvalue->value.ht);
  1997. }
  1998. }
  1999. break;
  2000. case IS_OBJECT:
  2001. {
  2002. TSRMLS_FETCH();
  2003. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  2004. GC_REMOVE_ZVAL_FROM_BUFFER(zvalue);
  2005. #endif
  2006. Z_OBJ_HT_P(zvalue)->del_ref(zvalue TSRMLS_CC);
  2007. }
  2008. break;
  2009. case IS_RESOURCE:
  2010. {
  2011. TSRMLS_FETCH();
  2012. /* destroy resource */
  2013. zend_list_delete(zvalue->value.lval);
  2014. }
  2015. break;
  2016. case IS_LONG:
  2017. case IS_DOUBLE:
  2018. case IS_BOOL:
  2019. case IS_NULL:
  2020. case IS_STRING:
  2021. case IS_CONSTANT:
  2022. default:
  2023. return;
  2024. break;
  2025. }
  2026. }
  2027. }
  2028. static int accel_clean_non_persistent_function(zend_function *function TSRMLS_DC)
  2029. {
  2030. if (function->type == ZEND_INTERNAL_FUNCTION) {
  2031. return ZEND_HASH_APPLY_STOP;
  2032. } else {
  2033. if (function->op_array.static_variables) {
  2034. function->op_array.static_variables->pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
  2035. accel_fast_hash_destroy(function->op_array.static_variables);
  2036. function->op_array.static_variables = NULL;
  2037. }
  2038. return (--(*function->op_array.refcount) <= 0) ?
  2039. ZEND_HASH_APPLY_REMOVE :
  2040. ZEND_HASH_APPLY_KEEP;
  2041. }
  2042. }
  2043. static int accel_cleanup_function_data(zend_function *function TSRMLS_DC)
  2044. {
  2045. if (function->type == ZEND_USER_FUNCTION) {
  2046. if (function->op_array.static_variables) {
  2047. function->op_array.static_variables->pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
  2048. accel_fast_hash_destroy(function->op_array.static_variables);
  2049. function->op_array.static_variables = NULL;
  2050. }
  2051. }
  2052. return 0;
  2053. }
  2054. static int accel_clean_non_persistent_class(zend_class_entry **pce TSRMLS_DC)
  2055. {
  2056. zend_class_entry *ce = *pce;
  2057. if (ce->type == ZEND_INTERNAL_CLASS) {
  2058. return ZEND_HASH_APPLY_STOP;
  2059. } else {
  2060. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  2061. if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
  2062. zend_hash_apply(&ce->function_table, (apply_func_t) accel_cleanup_function_data TSRMLS_CC);
  2063. }
  2064. if (ce->static_members_table) {
  2065. int i;
  2066. for (i = 0; i < ce->default_static_members_count; i++) {
  2067. if (ce->static_members_table[i]) {
  2068. accel_fast_zval_ptr_dtor(&ce->static_members_table[i]);
  2069. ce->static_members_table[i] = NULL;
  2070. }
  2071. }
  2072. ce->static_members_table = NULL;
  2073. }
  2074. #else
  2075. zend_hash_apply(&ce->function_table, (apply_func_t) accel_cleanup_function_data TSRMLS_CC);
  2076. if (ce->static_members) {
  2077. ce->static_members->pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
  2078. accel_fast_hash_destroy(ce->static_members);
  2079. ce->static_members = NULL;
  2080. }
  2081. #endif
  2082. return ZEND_HASH_APPLY_REMOVE;
  2083. }
  2084. }
  2085. static int accel_clean_non_persistent_constant(zend_constant *c TSRMLS_DC)
  2086. {
  2087. if (c->flags & CONST_PERSISTENT) {
  2088. return ZEND_HASH_APPLY_STOP;
  2089. } else {
  2090. interned_free(c->name);
  2091. return ZEND_HASH_APPLY_REMOVE;
  2092. }
  2093. }
  2094. static void zend_accel_fast_shutdown(TSRMLS_D)
  2095. {
  2096. if (EG(full_tables_cleanup)) {
  2097. EG(symbol_table).pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
  2098. } else {
  2099. dtor_func_t old_destructor;
  2100. if (EG(objects_store).top > 1 || zend_hash_num_elements(&EG(regular_list)) > 0) {
  2101. /* We don't have to destroy all zvals if they cannot call any destructors */
  2102. old_destructor = EG(symbol_table).pDestructor;
  2103. EG(symbol_table).pDestructor = (dtor_func_t)accel_fast_zval_ptr_dtor;
  2104. zend_try {
  2105. zend_hash_graceful_reverse_destroy(&EG(symbol_table));
  2106. } zend_end_try();
  2107. EG(symbol_table).pDestructor = old_destructor;
  2108. }
  2109. zend_hash_init(&EG(symbol_table), 0, NULL, NULL, 0);
  2110. old_destructor = EG(function_table)->pDestructor;
  2111. EG(function_table)->pDestructor = NULL;
  2112. zend_hash_reverse_apply(EG(function_table), (apply_func_t) accel_clean_non_persistent_function TSRMLS_CC);
  2113. EG(function_table)->pDestructor = old_destructor;
  2114. old_destructor = EG(class_table)->pDestructor;
  2115. EG(class_table)->pDestructor = NULL;
  2116. zend_hash_reverse_apply(EG(class_table), (apply_func_t) accel_clean_non_persistent_class TSRMLS_CC);
  2117. EG(class_table)->pDestructor = old_destructor;
  2118. old_destructor = EG(zend_constants)->pDestructor;
  2119. EG(zend_constants)->pDestructor = NULL;
  2120. zend_hash_reverse_apply(EG(zend_constants), (apply_func_t) accel_clean_non_persistent_constant TSRMLS_CC);
  2121. EG(zend_constants)->pDestructor = old_destructor;
  2122. }
  2123. CG(unclean_shutdown) = 1;
  2124. }
  2125. #endif
  2126. static void accel_deactivate(void)
  2127. {
  2128. /* ensure that we restore function_table and class_table
  2129. * In general, they're restored by persistent_compile_file(), but in case
  2130. * the script is aborted abnormally, they may become messed up.
  2131. */
  2132. TSRMLS_FETCH();
  2133. if (ZCG(cwd)) {
  2134. efree(ZCG(cwd));
  2135. ZCG(cwd) = NULL;
  2136. }
  2137. if (!ZCG(enabled) || !accel_startup_ok) {
  2138. return;
  2139. }
  2140. zend_shared_alloc_safe_unlock(TSRMLS_C); /* be sure we didn't leave cache locked */
  2141. accel_unlock_all(TSRMLS_C);
  2142. ZCG(counted) = 0;
  2143. #if !ZEND_DEBUG
  2144. if (ZCG(accel_directives).fast_shutdown) {
  2145. zend_accel_fast_shutdown(TSRMLS_C);
  2146. }
  2147. #endif
  2148. }
  2149. static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
  2150. {
  2151. (void)element2; /* keep the compiler happy */
  2152. if (!strcmp(element1->name, ACCELERATOR_PRODUCT_NAME )) {
  2153. element1->startup = NULL;
  2154. #if 0
  2155. /* We have to call shutdown callback it to free TS resources */
  2156. element1->shutdown = NULL;
  2157. #endif
  2158. element1->activate = NULL;
  2159. element1->deactivate = NULL;
  2160. element1->op_array_handler = NULL;
  2161. #ifdef __DEBUG_MESSAGES__
  2162. fprintf(stderr, ACCELERATOR_PRODUCT_NAME " is disabled: %s\n", (zps_failure_reason ? zps_failure_reason : "unknown error"));
  2163. fflush(stderr);
  2164. #endif
  2165. }
  2166. return 0;
  2167. }
  2168. static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_extension *, zend_extension *) TSRMLS_DC)
  2169. {
  2170. accel_startup_ok = 0;
  2171. zps_failure_reason = reason;
  2172. zps_api_failure_reason = api_reason?api_reason:reason;
  2173. zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb);
  2174. }
  2175. static inline int accel_find_sapi(TSRMLS_D)
  2176. {
  2177. static const char *supported_sapis[] = {
  2178. "apache",
  2179. "fastcgi",
  2180. "cli-server",
  2181. "cgi-fcgi",
  2182. "fpm-fcgi",
  2183. "isapi",
  2184. "apache2filter",
  2185. "apache2handler",
  2186. "litespeed",
  2187. "uwsgi",
  2188. NULL
  2189. };
  2190. const char **sapi_name;
  2191. if (sapi_module.name) {
  2192. for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
  2193. if (strcmp(sapi_module.name, *sapi_name) == 0) {
  2194. return SUCCESS;
  2195. }
  2196. }
  2197. if (ZCG(accel_directives).enable_cli &&
  2198. strcmp(sapi_module.name, "cli") == 0) {
  2199. return SUCCESS;
  2200. }
  2201. }
  2202. return FAILURE;
  2203. }
  2204. static int zend_accel_init_shm(TSRMLS_D)
  2205. {
  2206. zend_shared_alloc_lock(TSRMLS_C);
  2207. accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals));
  2208. if (!accel_shared_globals) {
  2209. zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
  2210. return FAILURE;
  2211. }
  2212. ZSMMG(app_shared_globals) = accel_shared_globals;
  2213. zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
  2214. zend_accel_hash_init(&ZCSG(include_paths), 32);
  2215. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  2216. ZCSG(interned_strings_start) = ZCSG(interned_strings_end) = NULL;
  2217. # ifndef ZTS
  2218. zend_hash_init(&ZCSG(interned_strings), (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024) / (sizeof(Bucket) + sizeof(Bucket*) + 8 /* average string length */), NULL, NULL, 1);
  2219. if (ZCG(accel_directives).interned_strings_buffer) {
  2220. ZCSG(interned_strings).nTableMask = ZCSG(interned_strings).nTableSize - 1;
  2221. ZCSG(interned_strings).arBuckets = zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(Bucket *));
  2222. ZCSG(interned_strings_start) = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024));
  2223. if (!ZCSG(interned_strings).arBuckets || !ZCSG(interned_strings_start)) {
  2224. zend_accel_error(ACCEL_LOG_FATAL, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings");
  2225. return FAILURE;
  2226. }
  2227. ZCSG(interned_strings_end) = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
  2228. ZCSG(interned_strings_top) = ZCSG(interned_strings_start);
  2229. orig_interned_strings_start = CG(interned_strings_start);
  2230. orig_interned_strings_end = CG(interned_strings_end);
  2231. CG(interned_strings_start) = ZCSG(interned_strings_start);
  2232. CG(interned_strings_end) = ZCSG(interned_strings_end);
  2233. }
  2234. # endif
  2235. orig_new_interned_string = zend_new_interned_string;
  2236. orig_interned_strings_snapshot = zend_interned_strings_snapshot;
  2237. orig_interned_strings_restore = zend_interned_strings_restore;
  2238. zend_new_interned_string = accel_new_interned_string_for_php;
  2239. zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
  2240. zend_interned_strings_restore = accel_interned_strings_restore_for_php;
  2241. # ifndef ZTS
  2242. if (ZCG(accel_directives).interned_strings_buffer) {
  2243. accel_use_shm_interned_strings(TSRMLS_C);
  2244. accel_interned_strings_save_state(TSRMLS_C);
  2245. }
  2246. # endif
  2247. #endif
  2248. zend_reset_cache_vars(TSRMLS_C);
  2249. ZCSG(oom_restarts) = 0;
  2250. ZCSG(hash_restarts) = 0;
  2251. ZCSG(manual_restarts) = 0;
  2252. ZCSG(accelerator_enabled) = 1;
  2253. ZCSG(start_time) = zend_accel_get_time();
  2254. ZCSG(last_restart_time) = 0;
  2255. ZCSG(restart_in_progress) = 0;
  2256. zend_shared_alloc_unlock(TSRMLS_C);
  2257. return SUCCESS;
  2258. }
  2259. static void accel_globals_ctor(zend_accel_globals *accel_globals TSRMLS_DC)
  2260. {
  2261. memset(accel_globals, 0, sizeof(zend_accel_globals));
  2262. zend_hash_init(&accel_globals->function_table, zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1);
  2263. zend_accel_copy_internal_functions(TSRMLS_C);
  2264. }
  2265. static void accel_globals_dtor(zend_accel_globals *accel_globals TSRMLS_DC)
  2266. {
  2267. accel_globals->function_table.pDestructor = NULL;
  2268. zend_hash_destroy(&accel_globals->function_table);
  2269. }
  2270. static int accel_startup(zend_extension *extension)
  2271. {
  2272. zend_function *func;
  2273. zend_ini_entry *ini_entry;
  2274. TSRMLS_FETCH();
  2275. #ifdef ZTS
  2276. accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor);
  2277. #else
  2278. accel_globals_ctor(&accel_globals);
  2279. #endif
  2280. #ifdef ZEND_WIN32
  2281. _setmaxstdio(2048); /* The default configuration is limited to 512 stdio files */
  2282. #endif
  2283. if (start_accel_module() == FAILURE) {
  2284. accel_startup_ok = 0;
  2285. zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
  2286. return FAILURE;
  2287. }
  2288. /* no supported SAPI found - disable acceleration and stop initialization */
  2289. if (accel_find_sapi(TSRMLS_C) == FAILURE) {
  2290. accel_startup_ok = 0;
  2291. if (!ZCG(accel_directives).enable_cli &&
  2292. strcmp(sapi_module.name, "cli") == 0) {
  2293. zps_startup_failure("Opcode Caching is disabled for CLI", NULL, accelerator_remove_cb TSRMLS_CC);
  2294. } else {
  2295. zps_startup_failure("Opcode Caching is only supported in Apache, ISAPI, FPM, FastCGI and LiteSpeed SAPIs", NULL, accelerator_remove_cb TSRMLS_CC);
  2296. }
  2297. return SUCCESS;
  2298. }
  2299. if (ZCG(enabled) == 0) {
  2300. return SUCCESS ;
  2301. }
  2302. /********************************************/
  2303. /* End of non-SHM dependent initializations */
  2304. /********************************************/
  2305. switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
  2306. case ALLOC_SUCCESS:
  2307. if (zend_accel_init_shm(TSRMLS_C) == FAILURE) {
  2308. accel_startup_ok = 0;
  2309. return FAILURE;
  2310. }
  2311. break;
  2312. case ALLOC_FAILURE:
  2313. accel_startup_ok = 0;
  2314. zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
  2315. return SUCCESS;
  2316. case SUCCESSFULLY_REATTACHED:
  2317. accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
  2318. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  2319. zend_shared_alloc_lock(TSRMLS_C);
  2320. orig_interned_strings_start = CG(interned_strings_start);
  2321. orig_interned_strings_end = CG(interned_strings_end);
  2322. orig_new_interned_string = zend_new_interned_string;
  2323. orig_interned_strings_snapshot = zend_interned_strings_snapshot;
  2324. orig_interned_strings_restore = zend_interned_strings_restore;
  2325. CG(interned_strings_start) = ZCSG(interned_strings_start);
  2326. CG(interned_strings_end) = ZCSG(interned_strings_end);
  2327. zend_new_interned_string = accel_new_interned_string_for_php;
  2328. zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
  2329. zend_interned_strings_restore = accel_interned_strings_restore_for_php;
  2330. # ifndef ZTS
  2331. accel_use_shm_interned_strings(TSRMLS_C);
  2332. # endif
  2333. zend_shared_alloc_unlock(TSRMLS_C);
  2334. #endif
  2335. break;
  2336. case FAILED_REATTACHED:
  2337. accel_startup_ok = 0;
  2338. zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
  2339. return SUCCESS;
  2340. break;
  2341. }
  2342. /* from this point further, shared memory is supposed to be OK */
  2343. /* Override compiler */
  2344. accelerator_orig_compile_file = zend_compile_file;
  2345. zend_compile_file = persistent_compile_file;
  2346. /* Override stream opener function (to eliminate open() call caused by
  2347. * include/require statements ) */
  2348. accelerator_orig_zend_stream_open_function = zend_stream_open_function;
  2349. zend_stream_open_function = persistent_stream_open_function;
  2350. #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
  2351. /* Override path resolver function (to eliminate stat() calls caused by
  2352. * include_once/require_once statements */
  2353. accelerator_orig_zend_resolve_path = zend_resolve_path;
  2354. zend_resolve_path = persistent_zend_resolve_path;
  2355. #endif
  2356. /* Override chdir() function */
  2357. if (zend_hash_find(CG(function_table), "chdir", sizeof("chdir"), (void**)&func) == SUCCESS &&
  2358. func->type == ZEND_INTERNAL_FUNCTION) {
  2359. orig_chdir = func->internal_function.handler;
  2360. func->internal_function.handler = ZEND_FN(accel_chdir);
  2361. }
  2362. ZCG(cwd) = NULL;
  2363. /* Override "include_path" modifier callback */
  2364. if (zend_hash_find(EG(ini_directives), "include_path", sizeof("include_path"), (void **) &ini_entry) == SUCCESS) {
  2365. ZCG(include_path) = INI_STR("include_path");
  2366. ZCG(include_path_key) = NULL;
  2367. if (ZCG(include_path) && *ZCG(include_path)) {
  2368. ZCG(include_path_len) = strlen(ZCG(include_path));
  2369. ZCG(include_path_key) = zend_accel_hash_find(&ZCSG(include_paths), ZCG(include_path), ZCG(include_path_len) + 1);
  2370. if (!ZCG(include_path_key) &&
  2371. !zend_accel_hash_is_full(&ZCSG(include_paths))) {
  2372. char *key;
  2373. zend_shared_alloc_lock(TSRMLS_C);
  2374. key = zend_shared_alloc(ZCG(include_path_len) + 2);
  2375. if (key) {
  2376. memcpy(key, ZCG(include_path), ZCG(include_path_len) + 1);
  2377. key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries;
  2378. ZCG(include_path_key) = key + ZCG(include_path_len) + 1;
  2379. zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key));
  2380. } else {
  2381. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC);
  2382. }
  2383. zend_shared_alloc_unlock(TSRMLS_C);
  2384. }
  2385. } else {
  2386. ZCG(include_path) = "";
  2387. ZCG(include_path_len) = 0;
  2388. }
  2389. orig_include_path_on_modify = ini_entry->on_modify;
  2390. ini_entry->on_modify = accel_include_path_on_modify;
  2391. }
  2392. zend_shared_alloc_lock(TSRMLS_C);
  2393. zend_shared_alloc_save_state();
  2394. zend_shared_alloc_unlock(TSRMLS_C);
  2395. SHM_PROTECT();
  2396. accel_startup_ok = 1;
  2397. /* Override file_exists(), is_file() and is_readable() */
  2398. zend_accel_override_file_functions(TSRMLS_C);
  2399. /* Load black list */
  2400. accel_blacklist.entries = NULL;
  2401. if (ZCG(enabled) && accel_startup_ok &&
  2402. ZCG(accel_directives).user_blacklist_filename &&
  2403. *ZCG(accel_directives.user_blacklist_filename)) {
  2404. zend_accel_blacklist_init(&accel_blacklist);
  2405. zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
  2406. }
  2407. #if 0
  2408. /* FIXME: We probably don't need it here */
  2409. zend_accel_copy_internal_functions(TSRMLS_C);
  2410. #endif
  2411. return SUCCESS;
  2412. }
  2413. static void accel_free_ts_resources()
  2414. {
  2415. #ifndef ZTS
  2416. accel_globals_dtor(&accel_globals);
  2417. #else
  2418. ts_free_id(accel_globals_id);
  2419. #endif
  2420. }
  2421. void accel_shutdown(TSRMLS_D)
  2422. {
  2423. zend_ini_entry *ini_entry;
  2424. zend_accel_blacklist_shutdown(&accel_blacklist);
  2425. if (!ZCG(enabled) || !accel_startup_ok) {
  2426. accel_free_ts_resources();
  2427. return;
  2428. }
  2429. #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
  2430. if (ZCG(accel_directives).interned_strings_buffer) {
  2431. # ifndef ZTS
  2432. zend_hash_clean(CG(function_table));
  2433. zend_hash_clean(CG(class_table));
  2434. zend_hash_clean(EG(zend_constants));
  2435. # endif
  2436. CG(interned_strings_start) = orig_interned_strings_start;
  2437. CG(interned_strings_end) = orig_interned_strings_end;
  2438. }
  2439. zend_new_interned_string = orig_new_interned_string;
  2440. zend_interned_strings_snapshot = orig_interned_strings_snapshot;
  2441. zend_interned_strings_restore = orig_interned_strings_restore;
  2442. #endif
  2443. accel_free_ts_resources();
  2444. zend_shared_alloc_shutdown();
  2445. zend_compile_file = accelerator_orig_compile_file;
  2446. if (zend_hash_find(EG(ini_directives), "include_path", sizeof("include_path"), (void **) &ini_entry) == SUCCESS) {
  2447. ini_entry->on_modify = orig_include_path_on_modify;
  2448. }
  2449. }
  2450. void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC)
  2451. {
  2452. if (ZCSG(restart_pending)) {
  2453. /* don't schedule twice */
  2454. return;
  2455. }
  2456. zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled!");
  2457. SHM_UNPROTECT();
  2458. ZCSG(restart_pending) = 1;
  2459. ZCSG(restart_reason) = reason;
  2460. ZCSG(cache_status_before_restart) = ZCSG(accelerator_enabled);
  2461. ZCSG(accelerator_enabled) = 0;
  2462. if (ZCG(accel_directives).force_restart_timeout) {
  2463. ZCSG(force_restart_time) = zend_accel_get_time() + ZCG(accel_directives).force_restart_timeout;
  2464. } else {
  2465. ZCSG(force_restart_time) = 0;
  2466. }
  2467. SHM_PROTECT();
  2468. }
  2469. /* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
  2470. #ifdef ZEND_WIN32
  2471. #define accel_deactivate_now() ZCG(counted) = 1; accel_deactivate_sub(TSRMLS_C)
  2472. #else
  2473. #define accel_deactivate_now() accel_deactivate_sub(TSRMLS_C)
  2474. #endif
  2475. /* ensures it is OK to read SHM
  2476. if it's not OK (restart in progress) returns FAILURE
  2477. if OK returns SUCCESS
  2478. MUST call accelerator_shm_read_unlock after done lock operations
  2479. */
  2480. int accelerator_shm_read_lock(TSRMLS_D)
  2481. {
  2482. if (ZCG(counted)) {
  2483. /* counted means we are holding read lock for SHM, so that nothing bad can happen */
  2484. return SUCCESS;
  2485. } else {
  2486. /* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
  2487. or is in progress now */
  2488. accel_activate_add(TSRMLS_C); /* acquire usage lock */
  2489. /* Now if we weren't inside restart, restart would not begin until we remove usage lock */
  2490. if (ZCSG(restart_in_progress)) {
  2491. /* we already were inside restart this means it's not safe to touch shm */
  2492. accel_deactivate_now(); /* drop usage lock */
  2493. return FAILURE;
  2494. }
  2495. }
  2496. return SUCCESS;
  2497. }
  2498. /* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
  2499. void accelerator_shm_read_unlock(TSRMLS_D)
  2500. {
  2501. if (!ZCG(counted)) {
  2502. /* counted is 0 - meaning we had to readlock manually, release readlock now */
  2503. accel_deactivate_now();
  2504. }
  2505. }
  2506. ZEND_EXT_API zend_extension zend_extension_entry = {
  2507. ACCELERATOR_PRODUCT_NAME, /* name */
  2508. ACCELERATOR_VERSION, /* version */
  2509. "Zend Technologies", /* author */
  2510. "http://www.zend.com/", /* URL */
  2511. "Copyright (c) 1999-2016", /* copyright */
  2512. accel_startup, /* startup */
  2513. NULL, /* shutdown */
  2514. accel_activate, /* per-script activation */
  2515. accel_deactivate, /* per-script deactivation */
  2516. NULL, /* message handler */
  2517. NULL, /* op_array handler */
  2518. NULL, /* extended statement handler */
  2519. NULL, /* extended fcall begin handler */
  2520. NULL, /* extended fcall end handler */
  2521. NULL, /* op_array ctor */
  2522. NULL, /* op_array dtor */
  2523. STANDARD_ZEND_EXTENSION_PROPERTIES
  2524. };